Textarea.svelte 1.6 KB

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