input.svelte 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. <script lang="ts">
  2. import { X } from '@lucide/svelte';
  3. import { flip } from 'svelte/animate';
  4. import type { ClassValue } from 'svelte/elements';
  5. import { Button } from '$lib/components/controls/button';
  6. import { Input } from '$lib/components/controls/input';
  7. let {
  8. disabled = false,
  9. value = $bindable(),
  10. placeholder,
  11. inputClass = '',
  12. class: className = '',
  13. }: {
  14. disabled?: boolean;
  15. value?: string[];
  16. placeholder?: string;
  17. inputClass?: ClassValue;
  18. class?: ClassValue;
  19. } = $props();
  20. let inputText = $state('');
  21. const addTag = () => {
  22. const v = inputText.trim();
  23. if (!v) return;
  24. if (value === undefined) value = [v];
  25. else if (!value.includes(v)) value.push(v);
  26. inputText = '';
  27. };
  28. </script>
  29. <div class={className}>
  30. {#if value !== undefined && value.length > 0}
  31. <div class="mb-2 flex flex-wrap gap-1">
  32. {#each value as item, i (item)}
  33. <span
  34. class="inline-flex items-center gap-1 rounded-full bg-white/10 px-2 py-1 text-xs text-white/75"
  35. animate:flip={{ duration: 100 }}
  36. >
  37. {item}
  38. <button
  39. class="opacity-25 hover:opacity-75"
  40. type="button"
  41. onclick={() => {
  42. if (value !== undefined) value.splice(i, 1);
  43. }}
  44. >
  45. <X size={12} strokeWidth={2} />
  46. </button>
  47. </span>
  48. {/each}
  49. </div>
  50. {/if}
  51. <div class="flex w-full items-center gap-2">
  52. <Input
  53. class={inputClass}
  54. {disabled}
  55. {placeholder}
  56. bind:value={inputText}
  57. onkeydown={(e) => {
  58. if (e.key === 'Enter') {
  59. e.preventDefault();
  60. addTag();
  61. }
  62. }}
  63. />
  64. <Button type="button" variant="outline" onclick={() => addTag()}>Add</Button>
  65. </div>
  66. </div>