@leaflink/stash 53.3.2 → 53.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Copy.js.map +1 -1
- package/package.json +1 -1
package/dist/Copy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Copy.js","sources":["../src/components/Copy/Copy.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import logger from '@leaflink/snitch';\n import { computed, ref, useCssModule, watch } from 'vue';\n\n import { UI_TIMEOUT } from '../../constants';\n import { t } from '../../locale';\n import Button from '../Button/Button.vue';\n import Icon from '../Icon/Icon.vue';\n import IconLabel from '../IconLabel/IconLabel.vue';\n import Tooltip from '../Tooltip/Tooltip.vue';\n\n export interface CopyProps {\n /**\n * Optional text to display instead of icon.\n */\n text?: string;\n\n /**\n * The value to copy to clipboard.\n */\n value: string;\n\n /**\n * Sets the copy icon or text to always be visible. By default, icon/text only appears when hovering over slot content.\n */\n visible?: boolean;\n\n /**\n * Sets the mode of the copy component.\n */\n // TODO: remove unset mode eventually but it will cause a breaking change\n mode?: 'icon' | 'text' | 'icon-button' | 'unset';\n }\n\n const props = withDefaults(defineProps<CopyProps>(), {\n text: undefined,\n visible: false,\n mode: 'unset',\n });\n\n /**\n * Compute the mode based on the props for backwards compatibility. Previously the checks were done\n * in the template based on text being present. Have to calculate it here after the text prop is set.\n */\n const computedMode = computed(() => {\n // If the mode is set, use it (new behavior)\n if (props.mode !== 'unset') return props.mode;\n\n // Otherwise, determine it based on the text prop (old behavior)\n return props.text ? 'text' : 'icon';\n });\n\n watch(\n [computedMode, () => props.text, () => props.visible],\n () => {\n // Validate the mode based on the text prop. This will still pass if the mode is unset but the text prop is present.\n if (!props.text && ['text', 'icon-button'].includes(computedMode.value)) {\n throw new Error('Copy: text prop is required when mode is text or icon-button');\n } else if (props.text && computedMode.value === 'icon') {\n throw new Error('Copy: text prop is not allowed when mode is icon');\n }\n\n // If the mode is icon-button and the visible prop is false,\n // warn the user that the visible prop is ignored when mode is icon-button\n // Because we have to show the whole control\n if (computedMode.value === 'icon-button' && props.visible === false) {\n logger.warn('Copy: visible prop is ignored when mode is icon-button');\n }\n },\n { immediate: true },\n );\n\n const emit = defineEmits<{\n /**\n * Emitted when the copy action is completed.\n */\n (e: 'copy'): void;\n }>();\n\n const classes = useCssModule();\n\n // Flag to indicate whether a user successfully copied the text to their clipboard.\n // Note: We reset this flag after a timeout to allow the user to copy the text multiple times.\n const isCopied = ref(false);\n\n const tooltip = computed(() => {\n return isCopied.value ? t('ll.copy.copied') : !props.text ? t('ll.copy.copyToClipboard') : null;\n });\n\n function handleCopy() {\n navigator.clipboard.writeText(props.value);\n isCopied.value = true;\n\n // Reset the copied state after the timeout to flip the icon back\n setTimeout(() => {\n isCopied.value = false;\n }, UI_TIMEOUT);\n\n emit('copy');\n }\n</script>\n\n<template>\n <div class=\"stash-copy flex items-center\" :class=\"{ [classes.hidden]: !props.visible }\" data-test=\"stash-copy\">\n <!-- If the mode is not icon-button, render the appropriate content based on the mode -->\n <template v-if=\"computedMode !== 'icon-button'\">\n <!-- @slot Anything you want to render. This is not what will be copied to the clipboard. -->\n <slot></slot>\n <Tooltip\n side=\"top\"\n :text=\"tooltip\"\n :is-disabled=\"!!props.text\"\n class=\"stash-copy__copy-zone ml-3 cursor-pointer\"\n :class=\"classes.copy\"\n data-test=\"stash-copy|copy-zone\"\n >\n <!-- Regardless of the mode, we always render ONLY the success icon if the text has been copied \n Which is why this is the first in the `v-if` block-->\n <Icon\n v-if=\"isCopied\"\n class=\"stash-copy__success-icon text-green-500\"\n name=\"circle-check\"\n data-test=\"stash-copy|success-icon\"\n />\n <!-- If the mode is text, we render a button with the text -->\n <Button\n v-else-if=\"computedMode === 'text'\"\n class=\"stash-copy__copy-text\"\n inline\n data-test=\"stash-copy|copy-target\"\n @click=\"handleCopy\"\n >\n {{ props.text }}\n </Button>\n <!-- If the mode is icon, we render just the icon -->\n <Icon\n v-else\n class=\"stash-copy__copy-icon\"\n name=\"copy\"\n title=\"Copy to clipboard\"\n data-test=\"stash-copy|copy-target\"\n @click=\"handleCopy\"\n />\n </Tooltip>\n </template>\n <template v-else>\n <!-- If the mode is icon-button, we render an icon button with the icon and text -->\n <Button\n icon-label\n :data-test=\"isCopied ? 'stash-copy|success-icon-button' : 'stash-copy|copy-target'\"\n :title=\"props.text\"\n :class=\"isCopied ? 'text-green-500' : ''\"\n @click=\"handleCopy\"\n >\n <IconLabel :icon=\"isCopied ? 'circle-check' : 'copy'\" :title=\"props.text\" stacked>\n {{ props.text }}\n </IconLabel>\n </Button>\n </template>\n </div>\n</template>\n\n<style module>\n @layer utilities {\n .hidden {\n .copy {\n visibility: hidden;\n }\n\n &:hover {\n .copy {\n visibility: visible;\n }\n }\n }\n }\n</style>\n"],"names":["props","__props","computedMode","computed","watch","logger","emit","__emit","classes","useCssModule","isCopied","ref","tooltip","t","handleCopy","UI_TIMEOUT"],"mappings":";;;;;;;;;;;;;;;;;;;AAkCE,UAAMA,IAAQC,GAURC,IAAeC,EAAS,MAExBH,EAAM,SAAS,UAAgBA,EAAM,OAGlCA,EAAM,OAAO,SAAS,MAC9B;
|
|
1
|
+
{"version":3,"file":"Copy.js","sources":["../src/components/Copy/Copy.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import logger from '@leaflink/snitch';\n import { computed, ref, useCssModule, watch } from 'vue';\n\n import { UI_TIMEOUT } from '../../constants';\n import { t } from '../../locale';\n import Button from '../Button/Button.vue';\n import Icon from '../Icon/Icon.vue';\n import IconLabel from '../IconLabel/IconLabel.vue';\n import Tooltip from '../Tooltip/Tooltip.vue';\n\n export interface CopyProps {\n /**\n * Optional text to display instead of icon.\n */\n text?: string;\n\n /**\n * The value to copy to clipboard.\n */\n value: string;\n\n /**\n * Sets the copy icon or text to always be visible. By default, icon/text only appears when hovering over slot content.\n */\n visible?: boolean;\n\n /**\n * Sets the mode of the copy component.\n */\n // TODO: remove unset mode eventually but it will cause a breaking change\n mode?: 'icon' | 'text' | 'icon-button' | 'unset';\n }\n\n const props = withDefaults(defineProps<CopyProps>(), {\n text: undefined,\n visible: false,\n mode: 'unset',\n });\n\n /**\n * Compute the mode based on the props for backwards compatibility. Previously the checks were done\n * in the template based on text being present. Have to calculate it here after the text prop is set.\n */\n const computedMode = computed(() => {\n // If the mode is set, use it (new behavior)\n if (props.mode !== 'unset') return props.mode;\n\n // Otherwise, determine it based on the text prop (old behavior)\n return props.text ? 'text' : 'icon';\n });\n\n // Watch the props individually to ensure we run validation when props change.\n watch(\n [computedMode, () => props.text, () => props.visible],\n () => {\n // Validate the mode based on the text prop. This will still pass if the mode is unset but the text prop is present.\n if (!props.text && ['text', 'icon-button'].includes(computedMode.value)) {\n throw new Error('Copy: text prop is required when mode is text or icon-button');\n } else if (props.text && computedMode.value === 'icon') {\n throw new Error('Copy: text prop is not allowed when mode is icon');\n }\n\n // If the mode is icon-button and the visible prop is false,\n // warn the user that the visible prop is ignored when mode is icon-button\n // Because we have to show the whole control\n if (computedMode.value === 'icon-button' && props.visible === false) {\n logger.warn('Copy: visible prop is ignored when mode is icon-button');\n }\n },\n { immediate: true },\n );\n\n const emit = defineEmits<{\n /**\n * Emitted when the copy action is completed.\n */\n (e: 'copy'): void;\n }>();\n\n const classes = useCssModule();\n\n // Flag to indicate whether a user successfully copied the text to their clipboard.\n // Note: We reset this flag after a timeout to allow the user to copy the text multiple times.\n const isCopied = ref(false);\n\n const tooltip = computed(() => {\n return isCopied.value ? t('ll.copy.copied') : !props.text ? t('ll.copy.copyToClipboard') : null;\n });\n\n function handleCopy() {\n navigator.clipboard.writeText(props.value);\n isCopied.value = true;\n\n // Reset the copied state after the timeout to flip the icon back\n setTimeout(() => {\n isCopied.value = false;\n }, UI_TIMEOUT);\n\n emit('copy');\n }\n</script>\n\n<template>\n <div class=\"stash-copy flex items-center\" :class=\"{ [classes.hidden]: !props.visible }\" data-test=\"stash-copy\">\n <!-- If the mode is not icon-button, render the appropriate content based on the mode -->\n <template v-if=\"computedMode !== 'icon-button'\">\n <!-- @slot Anything you want to render. This is not what will be copied to the clipboard. -->\n <slot></slot>\n <Tooltip\n side=\"top\"\n :text=\"tooltip\"\n :is-disabled=\"!!props.text\"\n class=\"stash-copy__copy-zone ml-3 cursor-pointer\"\n :class=\"classes.copy\"\n data-test=\"stash-copy|copy-zone\"\n >\n <!-- Regardless of the mode, we always render ONLY the success icon if the text has been copied \n Which is why this is the first in the `v-if` block-->\n <Icon\n v-if=\"isCopied\"\n class=\"stash-copy__success-icon text-green-500\"\n name=\"circle-check\"\n data-test=\"stash-copy|success-icon\"\n />\n <!-- If the mode is text, we render a button with the text -->\n <Button\n v-else-if=\"computedMode === 'text'\"\n class=\"stash-copy__copy-text\"\n inline\n data-test=\"stash-copy|copy-target\"\n @click=\"handleCopy\"\n >\n {{ props.text }}\n </Button>\n <!-- If the mode is icon, we render just the icon -->\n <Icon\n v-else\n class=\"stash-copy__copy-icon\"\n name=\"copy\"\n title=\"Copy to clipboard\"\n data-test=\"stash-copy|copy-target\"\n @click=\"handleCopy\"\n />\n </Tooltip>\n </template>\n <template v-else>\n <!-- If the mode is icon-button, we render an icon button with the icon and text -->\n <Button\n icon-label\n :data-test=\"isCopied ? 'stash-copy|success-icon-button' : 'stash-copy|copy-target'\"\n :title=\"props.text\"\n :class=\"isCopied ? 'text-green-500' : ''\"\n @click=\"handleCopy\"\n >\n <IconLabel :icon=\"isCopied ? 'circle-check' : 'copy'\" :title=\"props.text\" stacked>\n {{ props.text }}\n </IconLabel>\n </Button>\n </template>\n </div>\n</template>\n\n<style module>\n @layer utilities {\n .hidden {\n .copy {\n visibility: hidden;\n }\n\n &:hover {\n .copy {\n visibility: visible;\n }\n }\n }\n }\n</style>\n"],"names":["props","__props","computedMode","computed","watch","logger","emit","__emit","classes","useCssModule","isCopied","ref","tooltip","t","handleCopy","UI_TIMEOUT"],"mappings":";;;;;;;;;;;;;;;;;;;AAkCE,UAAMA,IAAQC,GAURC,IAAeC,EAAS,MAExBH,EAAM,SAAS,UAAgBA,EAAM,OAGlCA,EAAM,OAAO,SAAS,MAC9B;AAGD,IAAAI;AAAA,MACE,CAACF,GAAc,MAAMF,EAAM,MAAM,MAAMA,EAAM,OAAO;AAAA,MACpD,MAAM;AAEJ,YAAI,CAACA,EAAM,QAAQ,CAAC,QAAQ,aAAa,EAAE,SAASE,EAAa,KAAK;AACpE,gBAAM,IAAI,MAAM,8DAA8D;AAChF,YAAWF,EAAM,QAAQE,EAAa,UAAU;AAC9C,gBAAM,IAAI,MAAM,kDAAkD;AAMpE,QAAIA,EAAa,UAAU,iBAAiBF,EAAM,YAAY,MAC5DK,EAAO,KAAK,wDAAwD;AAAA,MAExE;AAAA,MACA,EAAE,WAAW,GAAA;AAAA,IAAK;AAGpB,UAAMC,IAAOC,GAOPC,IAAUC,EAAA,GAIVC,IAAWC,EAAI,EAAK,GAEpBC,IAAUT,EAAS,MAChBO,EAAS,QAAQG,EAAE,gBAAgB,IAAKb,EAAM,OAAsC,OAA/Ba,EAAE,yBAAyB,CACxF;AAED,aAASC,IAAa;AACpB,gBAAU,UAAU,UAAUd,EAAM,KAAK,GACzCU,EAAS,QAAQ,IAGjB,WAAW,MAAM;AACf,QAAAA,EAAS,QAAQ;AAAA,MACnB,GAAGK,CAAU,GAEbT,EAAK,MAAM;AAAA,IACb;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|