Textarea.svelte 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. <script lang="ts">
  2. import { onMount, tick } from 'svelte';
  3. export let value = '';
  4. export let placeholder = '';
  5. export let className =
  6. 'w-full rounded-lg px-3 py-2 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-none resize-none h-full';
  7. export let onKeydown: Function = () => {};
  8. let textareaElement;
  9. $: if (textareaElement) {
  10. if (textareaElement.innerText !== value && value !== '') {
  11. textareaElement.innerText = value ?? '';
  12. }
  13. }
  14. // Adjust height on mount and after setting the element.
  15. onMount(async () => {
  16. await tick();
  17. });
  18. // Handle paste event to ensure only plaintext is pasted
  19. function handlePaste(event: ClipboardEvent) {
  20. event.preventDefault(); // Prevent the default paste action
  21. const clipboardData = event.clipboardData?.getData('text/plain'); // Get plaintext from clipboard
  22. // Insert plaintext into the textarea
  23. document.execCommand('insertText', false, clipboardData);
  24. }
  25. </script>
  26. <div
  27. contenteditable="true"
  28. bind:this={textareaElement}
  29. class="{className} whitespace-pre-wrap relative {value
  30. ? !value.trim()
  31. ? 'placeholder'
  32. : ''
  33. : 'placeholder'}"
  34. style="field-sizing: content; -moz-user-select: text !important;"
  35. on:input={() => {
  36. const text = textareaElement.innerText;
  37. if (text === '\n') {
  38. value = '';
  39. return;
  40. }
  41. value = text;
  42. }}
  43. on:paste={handlePaste}
  44. on:keydown={onKeydown}
  45. data-placeholder={placeholder}
  46. />
  47. <style>
  48. .placeholder::before {
  49. /* abolute */
  50. position: absolute;
  51. content: attr(data-placeholder);
  52. color: #adb5bd;
  53. overflow: hidden;
  54. display: -webkit-box;
  55. -webkit-box-orient: vertical;
  56. -webkit-line-clamp: 1;
  57. pointer-events: none;
  58. touch-action: none;
  59. }
  60. </style>