flowbite-svelte 1.2.0 → 1.2.1

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.
Files changed (188) hide show
  1. package/dist/forms/floating-label-input/FloatingLabelInput.svelte +123 -4
  2. package/dist/forms/floating-label-input/FloatingLabelInput.svelte.d.ts +3 -0
  3. package/dist/forms/helper/Helper.svelte +1 -1
  4. package/dist/forms/helper/Helper.svelte.d.ts +1 -1
  5. package/dist/forms/input/Input.svelte +182 -21
  6. package/dist/forms/input/Input.svelte.d.ts +0 -5
  7. package/dist/forms/input-addon/InputAddon.svelte +1 -1
  8. package/dist/forms/input-addon/InputAddon.svelte.d.ts +1 -1
  9. package/dist/forms/label/Label.svelte +1 -1
  10. package/dist/forms/label/Label.svelte.d.ts +1 -1
  11. package/dist/forms/range/Range.svelte +1 -1
  12. package/dist/forms/range/Range.svelte.d.ts +1 -1
  13. package/dist/forms/search/Search.svelte +1 -1
  14. package/dist/forms/search/Search.svelte.d.ts +1 -1
  15. package/dist/forms/textarea/Textarea.svelte +1 -1
  16. package/dist/forms/textarea/Textarea.svelte.d.ts +1 -1
  17. package/dist/forms/timepicker/Timepicker.svelte +1 -1
  18. package/dist/forms/timepicker/Timepicker.svelte.d.ts +1 -1
  19. package/dist/forms/toggle/Toggle.svelte +1 -1
  20. package/dist/forms/toggle/Toggle.svelte.d.ts +1 -1
  21. package/dist/gallery/Gallery.svelte +1 -1
  22. package/dist/gallery/Gallery.svelte.d.ts +1 -1
  23. package/dist/indicator/Indicator.svelte +1 -1
  24. package/dist/indicator/Indicator.svelte.d.ts +1 -1
  25. package/dist/kbd/Kbd.svelte +1 -1
  26. package/dist/kbd/Kbd.svelte.d.ts +1 -1
  27. package/dist/list-group/Listgroup.svelte +1 -1
  28. package/dist/list-group/Listgroup.svelte.d.ts +1 -1
  29. package/dist/list-group/ListgroupItem.svelte +1 -1
  30. package/dist/list-group/ListgroupItem.svelte.d.ts +1 -1
  31. package/dist/mega-menu/MegaMenu.svelte +1 -1
  32. package/dist/mega-menu/MegaMenu.svelte.d.ts +1 -1
  33. package/dist/modal/Modal.svelte +1 -1
  34. package/dist/modal/Modal.svelte.d.ts +1 -1
  35. package/dist/navbar/Menu.svelte +1 -1
  36. package/dist/navbar/Menu.svelte.d.ts +1 -1
  37. package/dist/navbar/NavBrand.svelte +1 -1
  38. package/dist/navbar/NavBrand.svelte.d.ts +1 -1
  39. package/dist/navbar/NavContainer.svelte +1 -1
  40. package/dist/navbar/NavContainer.svelte.d.ts +1 -1
  41. package/dist/navbar/NavHamburger.svelte +1 -1
  42. package/dist/navbar/NavHamburger.svelte.d.ts +1 -1
  43. package/dist/navbar/NavLi.svelte +1 -1
  44. package/dist/navbar/NavLi.svelte.d.ts +1 -1
  45. package/dist/navbar/NavUl.svelte +1 -1
  46. package/dist/navbar/NavUl.svelte.d.ts +1 -1
  47. package/dist/navbar/Navbar.svelte +1 -1
  48. package/dist/navbar/Navbar.svelte.d.ts +1 -1
  49. package/dist/pagination/Pagination.svelte +1 -1
  50. package/dist/pagination/Pagination.svelte.d.ts +1 -1
  51. package/dist/pagination/PaginationItem.svelte +1 -1
  52. package/dist/pagination/PaginationItem.svelte.d.ts +1 -1
  53. package/dist/popover/Popover.svelte +1 -1
  54. package/dist/popover/Popover.svelte.d.ts +1 -1
  55. package/dist/progress/Progressbar.svelte +1 -1
  56. package/dist/progress/Progressbar.svelte.d.ts +1 -1
  57. package/dist/progress/Progressradial.svelte +1 -1
  58. package/dist/progress/Progressradial.svelte.d.ts +1 -1
  59. package/dist/rating/AdvancedRating.svelte +1 -1
  60. package/dist/rating/AdvancedRating.svelte.d.ts +1 -1
  61. package/dist/rating/CustomIcon.svelte +1 -1
  62. package/dist/rating/CustomIcon.svelte.d.ts +1 -1
  63. package/dist/rating/Heart.svelte +1 -1
  64. package/dist/rating/Heart.svelte.d.ts +1 -1
  65. package/dist/rating/Rating.svelte +1 -1
  66. package/dist/rating/Rating.svelte.d.ts +1 -1
  67. package/dist/rating/RatingComment.svelte +1 -1
  68. package/dist/rating/RatingComment.svelte.d.ts +1 -1
  69. package/dist/rating/Review.svelte +1 -1
  70. package/dist/rating/Review.svelte.d.ts +1 -1
  71. package/dist/rating/ScoreRating.svelte +1 -1
  72. package/dist/rating/ScoreRating.svelte.d.ts +1 -1
  73. package/dist/rating/Star.svelte +1 -1
  74. package/dist/rating/Star.svelte.d.ts +1 -1
  75. package/dist/rating/Thumbup.svelte +1 -1
  76. package/dist/rating/Thumbup.svelte.d.ts +1 -1
  77. package/dist/sidebar/Sidebar.svelte +1 -1
  78. package/dist/sidebar/Sidebar.svelte.d.ts +1 -1
  79. package/dist/sidebar/SidebarBrand.svelte +1 -1
  80. package/dist/sidebar/SidebarBrand.svelte.d.ts +1 -1
  81. package/dist/sidebar/SidebarButton.svelte +1 -1
  82. package/dist/sidebar/SidebarButton.svelte.d.ts +1 -1
  83. package/dist/sidebar/SidebarCta.svelte +1 -1
  84. package/dist/sidebar/SidebarCta.svelte.d.ts +1 -1
  85. package/dist/sidebar/SidebarDropdownWrapper.svelte +1 -1
  86. package/dist/sidebar/SidebarDropdownWrapper.svelte.d.ts +1 -1
  87. package/dist/sidebar/SidebarGroup.svelte +1 -1
  88. package/dist/sidebar/SidebarGroup.svelte.d.ts +1 -1
  89. package/dist/sidebar/SidebarItem.svelte +1 -1
  90. package/dist/sidebar/SidebarItem.svelte.d.ts +1 -1
  91. package/dist/skeleton/CardPlaceholder.svelte +1 -1
  92. package/dist/skeleton/CardPlaceholder.svelte.d.ts +1 -1
  93. package/dist/skeleton/ImagePlaceholder.svelte +1 -1
  94. package/dist/skeleton/ImagePlaceholder.svelte.d.ts +1 -1
  95. package/dist/skeleton/ListPlaceholder.svelte +1 -1
  96. package/dist/skeleton/ListPlaceholder.svelte.d.ts +1 -1
  97. package/dist/skeleton/Skeleton.svelte +1 -1
  98. package/dist/skeleton/Skeleton.svelte.d.ts +1 -1
  99. package/dist/skeleton/TextPlaceholder.svelte +1 -1
  100. package/dist/skeleton/TextPlaceholder.svelte.d.ts +1 -1
  101. package/dist/skeleton/VideoPlaceholder.svelte +1 -1
  102. package/dist/skeleton/VideoPlaceholder.svelte.d.ts +1 -1
  103. package/dist/speed-dial/SpeedDial.svelte +1 -1
  104. package/dist/speed-dial/SpeedDial.svelte.d.ts +1 -1
  105. package/dist/speed-dial/SpeedDialButton.svelte +1 -1
  106. package/dist/speed-dial/SpeedDialButton.svelte.d.ts +1 -1
  107. package/dist/speed-dial/SpeedDialTrigger.svelte +1 -1
  108. package/dist/speed-dial/SpeedDialTrigger.svelte.d.ts +1 -1
  109. package/dist/spinner/Spinner.svelte +1 -1
  110. package/dist/spinner/Spinner.svelte.d.ts +1 -1
  111. package/dist/steps/StepIndicator.svelte +1 -1
  112. package/dist/steps/StepIndicator.svelte.d.ts +1 -1
  113. package/dist/table/Table.svelte +1 -1
  114. package/dist/table/Table.svelte.d.ts +1 -1
  115. package/dist/table/TableBody.svelte +1 -1
  116. package/dist/table/TableBody.svelte.d.ts +1 -1
  117. package/dist/table/TableBodyCell.svelte +1 -1
  118. package/dist/table/TableBodyCell.svelte.d.ts +1 -1
  119. package/dist/table/TableBodyRow.svelte +1 -1
  120. package/dist/table/TableBodyRow.svelte.d.ts +1 -1
  121. package/dist/table/TableHead.svelte +1 -1
  122. package/dist/table/TableHead.svelte.d.ts +1 -1
  123. package/dist/table/TableHeadCell.svelte +1 -1
  124. package/dist/table/TableHeadCell.svelte.d.ts +1 -1
  125. package/dist/table/TableSearch.svelte +1 -1
  126. package/dist/table/TableSearch.svelte.d.ts +1 -1
  127. package/dist/tabs/TabItem.svelte +1 -1
  128. package/dist/tabs/TabItem.svelte.d.ts +1 -1
  129. package/dist/tabs/Tabs.svelte +1 -1
  130. package/dist/tabs/Tabs.svelte.d.ts +1 -1
  131. package/dist/theme/Theme.svelte +1 -1
  132. package/dist/theme/Theme.svelte.d.ts +1 -1
  133. package/dist/timeline/Activity.svelte +1 -1
  134. package/dist/timeline/Activity.svelte.d.ts +1 -1
  135. package/dist/timeline/ActivityItem.svelte +1 -1
  136. package/dist/timeline/ActivityItem.svelte.d.ts +1 -1
  137. package/dist/timeline/Group.svelte +1 -1
  138. package/dist/timeline/Group.svelte.d.ts +1 -1
  139. package/dist/timeline/GroupItem.svelte +1 -1
  140. package/dist/timeline/GroupItem.svelte.d.ts +1 -1
  141. package/dist/timeline/Timeline.svelte +1 -1
  142. package/dist/timeline/Timeline.svelte.d.ts +1 -1
  143. package/dist/timeline/TimelineItem.svelte +1 -1
  144. package/dist/timeline/TimelineItem.svelte.d.ts +1 -1
  145. package/dist/toast/Toast.svelte +1 -1
  146. package/dist/toast/Toast.svelte.d.ts +1 -1
  147. package/dist/toolbar/Toolbar.svelte +1 -1
  148. package/dist/toolbar/Toolbar.svelte.d.ts +1 -1
  149. package/dist/toolbar/ToolbarButton.svelte +1 -1
  150. package/dist/toolbar/ToolbarButton.svelte.d.ts +1 -1
  151. package/dist/toolbar/ToolbarGroup.svelte +1 -1
  152. package/dist/toolbar/ToolbarGroup.svelte.d.ts +1 -1
  153. package/dist/tooltip/Tooltip.svelte +1 -1
  154. package/dist/tooltip/Tooltip.svelte.d.ts +1 -1
  155. package/dist/types.d.ts +6 -0
  156. package/dist/typography/anchor/A.svelte +1 -1
  157. package/dist/typography/anchor/A.svelte.d.ts +1 -1
  158. package/dist/typography/blockquote/Blockquote.svelte +1 -1
  159. package/dist/typography/blockquote/Blockquote.svelte.d.ts +1 -1
  160. package/dist/typography/descriptionlist/DescriptionList.svelte +1 -1
  161. package/dist/typography/descriptionlist/DescriptionList.svelte.d.ts +1 -1
  162. package/dist/typography/heading/Heading.svelte +1 -1
  163. package/dist/typography/heading/Heading.svelte.d.ts +1 -1
  164. package/dist/typography/hr/Hr.svelte +1 -1
  165. package/dist/typography/hr/Hr.svelte.d.ts +1 -1
  166. package/dist/typography/img/EnhancedImg.svelte +1 -1
  167. package/dist/typography/img/EnhancedImg.svelte.d.ts +1 -1
  168. package/dist/typography/img/Img.svelte +1 -1
  169. package/dist/typography/img/Img.svelte.d.ts +1 -1
  170. package/dist/typography/layout/Layout.svelte +1 -1
  171. package/dist/typography/layout/Layout.svelte.d.ts +1 -1
  172. package/dist/typography/list/Li.svelte +1 -1
  173. package/dist/typography/list/Li.svelte.d.ts +1 -1
  174. package/dist/typography/list/List.svelte +1 -1
  175. package/dist/typography/list/List.svelte.d.ts +1 -1
  176. package/dist/typography/mark/Mark.svelte +1 -1
  177. package/dist/typography/mark/Mark.svelte.d.ts +1 -1
  178. package/dist/typography/paragraph/P.svelte +1 -1
  179. package/dist/typography/paragraph/P.svelte.d.ts +1 -1
  180. package/dist/typography/secondary/Secondary.svelte +1 -1
  181. package/dist/typography/secondary/Secondary.svelte.d.ts +1 -1
  182. package/dist/typography/span/Span.svelte +1 -1
  183. package/dist/typography/span/Span.svelte.d.ts +1 -1
  184. package/dist/utils/Popper.svelte +1 -1
  185. package/dist/utils/Popper.svelte.d.ts +1 -1
  186. package/dist/video/Video.svelte +1 -1
  187. package/dist/video/Video.svelte.d.ts +1 -1
  188. package/package.json +1 -1
@@ -4,27 +4,143 @@
4
4
  import { type FloatingLabelInputProps, CloseButton } from "../..";
5
5
  import clsx from "clsx";
6
6
 
7
- let { children, id = idGenerator(), value = $bindable(), elementRef = $bindable(), "aria-describedby": ariaDescribedby, variant = "standard", size = "default", color = "default", class: divClass, inputClass, labelClass, clearable, clearableSvgClass, clearableColor = "none", clearableClass, clearableOnClick, ...restProps }: FloatingLabelInputProps = $props();
7
+ let { children, id = idGenerator(), value = $bindable(), elementRef = $bindable(), "aria-describedby": ariaDescribedby, variant = "standard", size = "default", color = "default", class: divClass, inputClass, labelClass, clearable, clearableSvgClass, clearableColor = "none", clearableClass, clearableOnClick, data = [], maxSuggestions = 5, onSelect, ...restProps }: FloatingLabelInputProps = $props();
8
8
 
9
9
  const { base, input, label, clearbtn } = $derived(floatingLabelInput({ variant, size, color }));
10
10
 
11
11
  const clearAll = () => {
12
12
  if (elementRef) {
13
13
  elementRef.value = "";
14
- value = undefined;
14
+ value = "";
15
+ backspaceUsed = false;
16
+ updateSuggestions();
17
+ dummyFocusDiv?.focus();
18
+ setTimeout(() => {
19
+ elementRef?.focus();
20
+ }, 100);
15
21
  }
16
22
  if (clearableOnClick) clearableOnClick();
17
23
  };
24
+
25
+ const isCombobox = $derived(Array.isArray(data) && data.length > 0);
26
+
27
+ let dummyFocusDiv: HTMLDivElement;
28
+
29
+ let isFocused = $state(false);
30
+ let filteredSuggestions: string[] = $state([]);
31
+ let selectedIndex = $state(-1);
32
+ let backspaceUsed = $state(false);
33
+
34
+ function updateSuggestions() {
35
+ if (!isCombobox || !isFocused) {
36
+ filteredSuggestions = [];
37
+ return;
38
+ }
39
+
40
+ const searchTerm = ((value as string) || "").toLowerCase();
41
+
42
+ if (searchTerm === "" && !backspaceUsed) {
43
+ filteredSuggestions = [];
44
+ } else if (searchTerm) {
45
+ filteredSuggestions = data.filter((item) => item.toLowerCase().includes(searchTerm)).slice(0, maxSuggestions);
46
+ } else if (backspaceUsed) {
47
+ filteredSuggestions = [...data].slice(0, maxSuggestions);
48
+ }
49
+
50
+ selectedIndex = -1;
51
+ }
52
+
53
+ $effect(() => {
54
+ if (isCombobox) {
55
+ updateSuggestions();
56
+ }
57
+ });
58
+
59
+ function handleInput() {
60
+ if ((value as string).length > 0) {
61
+ backspaceUsed = false;
62
+ }
63
+ updateSuggestions();
64
+ }
65
+
66
+ function handleFocus() {
67
+ isFocused = true;
68
+ updateSuggestions();
69
+ }
70
+
71
+ function handleBlur() {
72
+ setTimeout(() => {
73
+ isFocused = false;
74
+ backspaceUsed = false;
75
+ filteredSuggestions = [];
76
+ }, 200);
77
+ }
78
+
79
+ function handleKeydown(event: KeyboardEvent) {
80
+ if (!isCombobox) return;
81
+
82
+ if (event.key === "Backspace" || event.key === "Delete") {
83
+ const currentValue = value as string;
84
+ if (currentValue.length <= 1) {
85
+ backspaceUsed = true;
86
+ }
87
+ }
88
+
89
+ if (!filteredSuggestions.length) return;
90
+
91
+ switch (event.key) {
92
+ case "ArrowDown":
93
+ event.preventDefault();
94
+ selectedIndex = (selectedIndex + 1) % filteredSuggestions.length;
95
+ break;
96
+ case "ArrowUp":
97
+ event.preventDefault();
98
+ selectedIndex = selectedIndex <= 0 ? filteredSuggestions.length - 1 : selectedIndex - 1;
99
+ break;
100
+ case "Enter":
101
+ if (selectedIndex >= 0) {
102
+ event.preventDefault();
103
+ selectItem(filteredSuggestions[selectedIndex]);
104
+ }
105
+ break;
106
+ case "Escape":
107
+ event.preventDefault();
108
+ filteredSuggestions = [];
109
+ break;
110
+ }
111
+ }
112
+
113
+ function selectItem(item: string) {
114
+ value = item;
115
+ if (onSelect) onSelect(item);
116
+ filteredSuggestions = [];
117
+ selectedIndex = -1;
118
+ elementRef?.focus();
119
+ }
18
120
  </script>
19
121
 
20
- <div class={base({ class: clsx(divClass) })}>
21
- <input {id} placeholder=" " bind:value bind:this={elementRef} {...restProps} aria-describedby={ariaDescribedby} class={input({ class: inputClass })} />
122
+ {#if clearable}
123
+ <div tabindex="-1" bind:this={dummyFocusDiv} class="sr-only"></div>
124
+ {/if}
125
+
126
+ <div class={clsx(base({ class: divClass }), isCombobox ? "relative" : "")}>
127
+ <input {id} placeholder=" " bind:value bind:this={elementRef} {...restProps} aria-describedby={ariaDescribedby} class={input({ class: inputClass })} oninput={handleInput} onfocus={handleFocus} onblur={handleBlur} onkeydown={handleKeydown} />
22
128
  {#if value !== undefined && value !== "" && clearable}
23
129
  <CloseButton onclick={clearAll} class={clearbtn({ class: clearableClass })} color={clearableColor} aria-label="Clear search value" svgClass={clearableSvgClass} />
24
130
  {/if}
25
131
  <label for={id} class={label({ class: labelClass })}>
26
132
  {@render children()}
27
133
  </label>
134
+
135
+ {#if isCombobox && isFocused && filteredSuggestions.length > 0}
136
+ <div class="absolute top-full right-0 left-0 z-10 mt-1 max-h-60 overflow-y-auto rounded-md border border-gray-200 bg-white shadow-lg dark:border-gray-700 dark:bg-gray-800">
137
+ {#each filteredSuggestions as item, i}
138
+ <button type="button" class="w-full px-3 py-2 text-left {i === selectedIndex ? 'bg-gray-100 dark:bg-gray-700' : 'hover:bg-gray-50 dark:hover:bg-gray-700'} focus:outline-none" onclick={() => selectItem(item)} onmouseenter={() => (selectedIndex = i)}>
139
+ {item}
140
+ </button>
141
+ {/each}
142
+ </div>
143
+ {/if}
28
144
  </div>
29
145
 
30
146
  <!--
@@ -49,5 +165,8 @@
49
165
  @prop clearableColor = "none"
50
166
  @prop clearableClass
51
167
  @prop clearableOnClick
168
+ @prop data = []
169
+ @prop maxSuggestions = 5
170
+ @prop onSelect
52
171
  @prop ...restProps
53
172
  -->
@@ -20,6 +20,9 @@ import { type FloatingLabelInputProps } from "../..";
20
20
  * @prop clearableColor = "none"
21
21
  * @prop clearableClass
22
22
  * @prop clearableOnClick
23
+ * @prop data = []
24
+ * @prop maxSuggestions = 5
25
+ * @prop onSelect
23
26
  * @prop ...restProps
24
27
  */
25
28
  declare const FloatingLabelInput: import("svelte").Component<FloatingLabelInputProps, {}, "value" | "elementRef">;
@@ -16,7 +16,7 @@
16
16
  @component
17
17
  [Go to docs](https://flowbite-svelte.com/)
18
18
  ## Type
19
- [HelperProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L725)
19
+ [HelperProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L728)
20
20
  ## Props
21
21
  @prop children
22
22
  @prop class: className
@@ -2,7 +2,7 @@ import type { HelperProps } from "../../types";
2
2
  /**
3
3
  * [Go to docs](https://flowbite-svelte.com/)
4
4
  * ## Type
5
- * [HelperProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L725)
5
+ * [HelperProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L728)
6
6
  * ## Props
7
7
  * @prop children
8
8
  * @prop class: className
@@ -4,11 +4,39 @@
4
4
  import { input, clampSize } from ".";
5
5
  import clsx from "clsx";
6
6
 
7
- let { children, left, right, value = $bindable(), elementRef = $bindable(), clearable = false, size, color = "default", class: className, classLeft, classRight, divClass, clearableSvgClass, clearableColor = "none", clearableClass, clearableOnClick, ...restProps }: InputProps<InputValue> = $props();
7
+ let {
8
+ children,
9
+ left,
10
+ right,
11
+ value = $bindable(),
12
+ elementRef = $bindable(),
13
+ clearable = false,
14
+ size,
15
+ color = "default",
16
+ class: className,
17
+ classLeft,
18
+ classRight,
19
+ divClass,
20
+ clearableSvgClass,
21
+ clearableColor = "none",
22
+ clearableClass,
23
+ clearableOnClick,
24
+ // Combobox props
25
+ data = [],
26
+ maxSuggestions = 5,
27
+ onSelect,
28
+ ...restProps
29
+ }: InputProps<InputValue> = $props();
30
+
31
+ // Automatically enable combobox when data is provided
32
+ const isCombobox = $derived(Array.isArray(data) && data.length > 0);
8
33
 
9
34
  // tinted if put in component having its own background
10
35
  let background: boolean = getContext("background");
11
36
 
37
+ // svelte-ignore non_reactive_update
38
+ let dummyFocusDiv: HTMLDivElement;
39
+
12
40
  let group: { size: SizeType } = getContext("group");
13
41
  let isGroup = !!group;
14
42
  let _size = $derived(size || clampSize(group?.size) || "md");
@@ -18,13 +46,163 @@
18
46
 
19
47
  const clearAll = () => {
20
48
  if (elementRef) {
21
- elementRef.value = "";
22
- value = undefined;
49
+ // in order to avoid type error in setTimeout()
50
+ const input = elementRef;
51
+ input.value = "";
52
+ value = "";
53
+
54
+ backspaceUsed = false;
55
+ updateSuggestions();
56
+ // hack to focus outside
57
+ dummyFocusDiv?.focus();
58
+ setTimeout(() => {
59
+ input.focus();
60
+ }, 100);
23
61
  }
62
+
24
63
  if (clearableOnClick) clearableOnClick();
25
64
  };
65
+
66
+ // Combobox functionality
67
+ let isFocused = $state(false);
68
+ let filteredSuggestions: string[] = $state([]);
69
+ let selectedIndex = $state(-1);
70
+ let backspaceUsed = $state(false); // Track if backspace was used to clear
71
+
72
+ function updateSuggestions() {
73
+ if (!isCombobox || !isFocused) {
74
+ filteredSuggestions = [];
75
+ return;
76
+ }
77
+
78
+ const searchTerm = ((value as string) || "").toLowerCase();
79
+
80
+ // Show suggestions if:
81
+ // 1. There's actual input text, OR
82
+ // 2. The input is empty but backspace was just used to clear it
83
+ if (searchTerm === "" && !backspaceUsed) {
84
+ filteredSuggestions = [];
85
+ } else {
86
+ // If there's text, filter suggestions
87
+ if (searchTerm) {
88
+ filteredSuggestions = data.filter((item) => item.toLowerCase().includes(searchTerm)).slice(0, maxSuggestions);
89
+ }
90
+ // If empty but backspace was used, show all suggestions
91
+ else if (backspaceUsed) {
92
+ filteredSuggestions = [...data].slice(0, maxSuggestions);
93
+ }
94
+ }
95
+
96
+ selectedIndex = -1;
97
+ }
98
+
99
+ // Watch for value changes
100
+ $effect(() => {
101
+ if (isCombobox) {
102
+ updateSuggestions();
103
+ }
104
+ });
105
+
106
+ function handleInput() {
107
+ // Reset backspace flag if user starts typing again
108
+ if ((value as string).length > 0) {
109
+ backspaceUsed = false;
110
+ }
111
+ updateSuggestions();
112
+ }
113
+
114
+ function handleFocus() {
115
+ isFocused = true;
116
+ updateSuggestions();
117
+ }
118
+
119
+ function handleBlur() {
120
+ // Small delay to allow click on suggestion to fire first
121
+ setTimeout(() => {
122
+ isFocused = false;
123
+ backspaceUsed = false; // Reset flag when focus is lost
124
+ filteredSuggestions = [];
125
+ }, 200);
126
+ }
127
+
128
+ function handleKeydown(event: KeyboardEvent) {
129
+ if (!isCombobox) return;
130
+
131
+ // Special handling for backspace/delete - track when it's used to clear the input
132
+ if (event.key === "Backspace" || event.key === "Delete") {
133
+ const currentValue = value as string;
134
+ // If this keypress will make the input empty
135
+ if (currentValue.length <= 1) {
136
+ backspaceUsed = true;
137
+ }
138
+ }
139
+
140
+ if (!filteredSuggestions.length) return;
141
+
142
+ switch (event.key) {
143
+ case "ArrowDown":
144
+ event.preventDefault();
145
+ selectedIndex = (selectedIndex + 1) % filteredSuggestions.length;
146
+ break;
147
+ case "ArrowUp":
148
+ event.preventDefault();
149
+ selectedIndex = selectedIndex <= 0 ? filteredSuggestions.length - 1 : selectedIndex - 1;
150
+ break;
151
+ case "Enter":
152
+ if (selectedIndex >= 0) {
153
+ event.preventDefault();
154
+ selectItem(filteredSuggestions[selectedIndex]);
155
+ }
156
+ break;
157
+ case "Escape":
158
+ event.preventDefault();
159
+ filteredSuggestions = [];
160
+ break;
161
+ }
162
+ }
163
+
164
+ function selectItem(item: string) {
165
+ value = item;
166
+
167
+ if (onSelect) {
168
+ onSelect(item);
169
+ }
170
+
171
+ filteredSuggestions = [];
172
+ selectedIndex = -1;
173
+
174
+ if (elementRef) {
175
+ elementRef.focus();
176
+ }
177
+ }
26
178
  </script>
27
179
 
180
+ {#if clearable}
181
+ <div tabindex="-1" bind:this={dummyFocusDiv} class="sr-only"></div>
182
+ {/if}
183
+
184
+ <div class={isCombobox ? "relative w-full" : ""}>
185
+ {#if group}
186
+ {@render inputContent()}
187
+ {:else if right || left || clearable}
188
+ <div class={base({ class: divClass })}>
189
+ {@render inputContent()}
190
+ </div>
191
+ {:else}
192
+ {@render inputContent()}
193
+ {/if}
194
+
195
+ {#if isCombobox && isFocused && filteredSuggestions.length > 0}
196
+ <div class="absolute top-full right-0 left-0 z-10 mt-1 max-h-60 overflow-y-auto rounded-md border border-gray-200 bg-white shadow-lg dark:border-gray-700 dark:bg-gray-800">
197
+ {#each filteredSuggestions as item, i}
198
+ <button type="button" class="w-full px-3 py-2 text-left {i === selectedIndex ? 'bg-gray-100 dark:bg-gray-700' : 'hover:bg-gray-50 dark:hover:bg-gray-700'} focus:outline-none" onclick={() => selectItem(item)} onmouseenter={() => (selectedIndex = i)}>
199
+ {item}
200
+ </button>
201
+ {/each}
202
+ </div>
203
+ {/if}
204
+ </div>
205
+
28
206
  {#snippet inputContent()}
29
207
  {#if left}
30
208
  <div class={leftCls({ class: classLeft })}>
@@ -34,7 +212,7 @@
34
212
  {#if children}
35
213
  {@render children({ ...restProps, class: inputCls() })}
36
214
  {:else}
37
- <input {...restProps} bind:value bind:this={elementRef} class={inputCls({ class: clsx(className) })} />
215
+ <input {...restProps} bind:value bind:this={elementRef} oninput={handleInput} onfocus={handleFocus} onblur={handleBlur} onkeydown={handleKeydown} class={inputCls({ class: clsx(className) })} />
38
216
  {#if value !== undefined && value !== "" && clearable}
39
217
  <CloseButton onclick={clearAll} class={clearbtn({ class: clearableClass })} color={clearableColor} aria-label="Clear search value" svgClass={clearableSvgClass} />
40
218
  {/if}
@@ -45,20 +223,3 @@
45
223
  </div>
46
224
  {/if}
47
225
  {/snippet}
48
-
49
- {#if group}
50
- {@render inputContent()}
51
- {:else if right || left || clearable}
52
- <div class={base({ class: divClass })}>
53
- {@render inputContent()}
54
- </div>
55
- {:else}
56
- {@render inputContent()}
57
- {/if}
58
-
59
- <!--
60
- @component
61
- [Go to docs](https://flowbite-svelte.com/)
62
- ## Props
63
- @props:
64
- -->
@@ -1,9 +1,4 @@
1
1
  import { type InputProps, type InputValue } from "../..";
2
- /**
3
- * [Go to docs](https://flowbite-svelte.com/)
4
- * ## Props
5
- * @props:
6
- */
7
2
  declare const Input: import("svelte").Component<InputProps<InputValue>, {}, "value" | "elementRef">;
8
3
  type Input = ReturnType<typeof Input>;
9
4
  export default Input;
@@ -41,7 +41,7 @@
41
41
  @component
42
42
  [Go to docs](https://flowbite-svelte.com/)
43
43
  ## Type
44
- [InputAddonProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L749)
44
+ [InputAddonProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L755)
45
45
  ## Props
46
46
  @prop children
47
47
  @prop class: className
@@ -2,7 +2,7 @@ import type { InputAddonProps } from "../../types";
2
2
  /**
3
3
  * [Go to docs](https://flowbite-svelte.com/)
4
4
  * ## Type
5
- * [InputAddonProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L749)
5
+ * [InputAddonProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L755)
6
6
  * ## Props
7
7
  * @prop children
8
8
  * @prop class: className
@@ -20,7 +20,7 @@
20
20
  @component
21
21
  [Go to docs](https://flowbite-svelte.com/)
22
22
  ## Type
23
- [LabelProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L756)
23
+ [LabelProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L762)
24
24
  ## Props
25
25
  @prop children
26
26
  @prop color = "gray"
@@ -2,7 +2,7 @@ import type { LabelProps } from "../../types";
2
2
  /**
3
3
  * [Go to docs](https://flowbite-svelte.com/)
4
4
  * ## Type
5
- * [LabelProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L756)
5
+ * [LabelProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L762)
6
6
  * ## Props
7
7
  * @prop children
8
8
  * @prop color = "gray"
@@ -14,7 +14,7 @@
14
14
  @component
15
15
  [Go to docs](https://flowbite-svelte.com/)
16
16
  ## Type
17
- [RangeProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L785)
17
+ [RangeProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L791)
18
18
  ## Props
19
19
  @prop value = $bindable()
20
20
  @prop appearance = "none"
@@ -2,7 +2,7 @@ import type { RangeProps } from "../../types";
2
2
  /**
3
3
  * [Go to docs](https://flowbite-svelte.com/)
4
4
  * ## Type
5
- * [RangeProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L785)
5
+ * [RangeProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L791)
6
6
  * ## Props
7
7
  * @prop value = $bindable()
8
8
  * @prop appearance = "none"
@@ -37,7 +37,7 @@
37
37
  @component
38
38
  [Go to docs](https://flowbite-svelte.com/)
39
39
  ## Type
40
- [SearchProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L790)
40
+ [SearchProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L796)
41
41
  ## Props
42
42
  @prop children
43
43
  @prop class: inputClass
@@ -2,7 +2,7 @@ import { type SearchProps } from "../..";
2
2
  /**
3
3
  * [Go to docs](https://flowbite-svelte.com/)
4
4
  * ## Type
5
- * [SearchProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L790)
5
+ * [SearchProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L796)
6
6
  * ## Props
7
7
  * @prop children
8
8
  * @prop class: inputClass
@@ -49,7 +49,7 @@
49
49
  @component
50
50
  [Go to docs](https://flowbite-svelte.com/)
51
51
  ## Type
52
- [TextareaProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L868)
52
+ [TextareaProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L874)
53
53
  ## Props
54
54
  @prop header
55
55
  @prop footer
@@ -2,7 +2,7 @@ import { type TextareaProps } from "../..";
2
2
  /**
3
3
  * [Go to docs](https://flowbite-svelte.com/)
4
4
  * ## Type
5
- * [TextareaProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L868)
5
+ * [TextareaProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L874)
6
6
  * ## Props
7
7
  * @prop header
8
8
  * @prop footer
@@ -195,7 +195,7 @@
195
195
  @component
196
196
  [Go to docs](https://flowbite-svelte.com/)
197
197
  ## Type
198
- [TimepickerProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L840)
198
+ [TimepickerProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L846)
199
199
  ## Props
200
200
  @prop id = "time"
201
201
  @prop endId = "end-time"
@@ -2,7 +2,7 @@ import { type TimepickerProps } from "../..";
2
2
  /**
3
3
  * [Go to docs](https://flowbite-svelte.com/)
4
4
  * ## Type
5
- * [TimepickerProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L840)
5
+ * [TimepickerProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L846)
6
6
  * ## Props
7
7
  * @prop id = "time"
8
8
  * @prop endId = "end-time"
@@ -24,7 +24,7 @@
24
24
  @component
25
25
  [Go to docs](https://flowbite-svelte.com/)
26
26
  ## Type
27
- [ToggleProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L887)
27
+ [ToggleProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L893)
28
28
  ## Props
29
29
  @prop children
30
30
  @prop size = "default"
@@ -2,7 +2,7 @@ import type { ToggleProps } from "../../types";
2
2
  /**
3
3
  * [Go to docs](https://flowbite-svelte.com/)
4
4
  * ## Type
5
- * [ToggleProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L887)
5
+ * [ToggleProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L893)
6
6
  * ## Props
7
7
  * @prop children
8
8
  * @prop size = "default"
@@ -36,7 +36,7 @@
36
36
  @component
37
37
  [Go to docs](https://flowbite-svelte.com/)
38
38
  ## Type
39
- [GalleryProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L904)
39
+ [GalleryProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L910)
40
40
  ## Props
41
41
  @prop children
42
42
  @prop figure
@@ -2,7 +2,7 @@ import type { GalleryProps } from "../types";
2
2
  /**
3
3
  * [Go to docs](https://flowbite-svelte.com/)
4
4
  * ## Type
5
- * [GalleryProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L904)
5
+ * [GalleryProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L910)
6
6
  * ## Props
7
7
  * @prop children
8
8
  * @prop figure
@@ -29,7 +29,7 @@
29
29
  @component
30
30
  [Go to docs](https://flowbite-svelte.com/)
31
31
  ## Type
32
- [IndicatorProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L912)
32
+ [IndicatorProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L918)
33
33
  ## Props
34
34
  @prop children
35
35
  @prop color = "primary"
@@ -2,7 +2,7 @@ import type { IndicatorProps } from "../types";
2
2
  /**
3
3
  * [Go to docs](https://flowbite-svelte.com/)
4
4
  * ## Type
5
- * [IndicatorProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L912)
5
+ * [IndicatorProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L918)
6
6
  * ## Props
7
7
  * @prop children
8
8
  * @prop color = "primary"
@@ -15,7 +15,7 @@
15
15
  @component
16
16
  [Go to docs](https://flowbite-svelte.com/)
17
17
  ## Type
18
- [KbdProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L923)
18
+ [KbdProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L929)
19
19
  ## Props
20
20
  @prop children
21
21
  @prop class: className
@@ -2,7 +2,7 @@ import type { KbdProps } from "../types";
2
2
  /**
3
3
  * [Go to docs](https://flowbite-svelte.com/)
4
4
  * ## Type
5
- * [KbdProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L923)
5
+ * [KbdProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L929)
6
6
  * ## Props
7
7
  * @prop children
8
8
  * @prop class: className
@@ -44,7 +44,7 @@
44
44
  @component
45
45
  [Go to docs](https://flowbite-svelte.com/)
46
46
  ## Type
47
- [ListgroupProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L942)
47
+ [ListgroupProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L948)
48
48
  ## Props
49
49
  @prop children
50
50
  @prop items
@@ -2,7 +2,7 @@ import type { ListgroupProps } from "../types";
2
2
  /**
3
3
  * [Go to docs](https://flowbite-svelte.com/)
4
4
  * ## Type
5
- * [ListgroupProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L942)
5
+ * [ListgroupProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L948)
6
6
  * ## Props
7
7
  * @prop children
8
8
  * @prop items