Textarea.svelte 1.6 KB

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