@placeholderco/placeholder-ui 1.0.12 → 2.0.0

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 (276) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +134 -130
  3. package/dist/app.css +178 -0
  4. package/dist/bootstrap.min.css +3600 -0
  5. package/dist/cards/GitCard.svelte +115 -0
  6. package/dist/cards/GitCard.svelte.d.ts +22 -0
  7. package/dist/display/Avatar.svelte +29 -17
  8. package/dist/display/Avatar.svelte.d.ts +12 -2
  9. package/dist/display/LinkCollection.svelte +40 -18
  10. package/dist/display/LinkCollection.svelte.d.ts +9 -2
  11. package/dist/display/Paper.svelte +31 -19
  12. package/dist/display/Paper.svelte.d.ts +12 -3
  13. package/dist/display/alert/Alert.svelte +129 -0
  14. package/dist/display/alert/Alert.svelte.d.ts +15 -0
  15. package/dist/display/alert/AlertVariant.d.ts +1 -0
  16. package/dist/display/alert/AlertVariant.js +1 -0
  17. package/dist/display/filetree/FileTree.svelte +259 -0
  18. package/dist/display/filetree/FileTree.svelte.d.ts +76 -0
  19. package/dist/display/filetree/FileTreeItem.svelte +396 -0
  20. package/dist/display/filetree/FileTreeItem.svelte.d.ts +40 -0
  21. package/dist/display/filetree/FileTreeNode.d.ts +46 -0
  22. package/dist/display/filetree/FileTreeNode.js +115 -0
  23. package/dist/display/filetree/index.d.ts +5 -0
  24. package/dist/display/filetree/index.js +3 -0
  25. package/dist/editors/CodeMirror.svelte +306 -0
  26. package/dist/editors/CodeMirror.svelte.d.ts +31 -0
  27. package/dist/editors/tiptap/LinkActionMenu.svelte +307 -0
  28. package/dist/editors/tiptap/LinkActionMenu.svelte.d.ts +8 -0
  29. package/dist/editors/tiptap/TipTap.svelte +856 -0
  30. package/dist/editors/tiptap/TipTap.svelte.d.ts +54 -0
  31. package/dist/editors/tiptap/TipTapBubble.svelte +790 -0
  32. package/dist/editors/tiptap/TipTapBubble.svelte.d.ts +44 -0
  33. package/dist/editors/tiptap/collaboration.d.ts +55 -0
  34. package/dist/editors/tiptap/collaboration.js +1 -0
  35. package/dist/editors/tiptap/extensions/Alert.d.ts +18 -0
  36. package/dist/editors/tiptap/extensions/Alert.js +72 -0
  37. package/dist/editors/tiptap/extensions/CodeBlockEditor.d.ts +21 -0
  38. package/dist/editors/tiptap/extensions/CodeBlockEditor.js +326 -0
  39. package/dist/editors/tiptap/extensions/Div.d.ts +19 -0
  40. package/dist/editors/tiptap/extensions/Div.js +89 -0
  41. package/dist/editors/tiptap/extensions/Span.d.ts +5 -0
  42. package/dist/editors/tiptap/extensions/Span.js +56 -0
  43. package/dist/editors/tiptap/extensions/codeBlockEditor.css +236 -0
  44. package/dist/editors/tiptap/extensions/codeBlockLanguages.d.ts +17 -0
  45. package/dist/editors/tiptap/extensions/codeBlockLanguages.js +124 -0
  46. package/dist/editors/tiptap/extensions/index.d.ts +7 -0
  47. package/dist/editors/tiptap/extensions/index.js +5 -0
  48. package/dist/editors/tiptap/toolbar/AlertButton.svelte +261 -0
  49. package/dist/editors/tiptap/toolbar/AlertButton.svelte.d.ts +7 -0
  50. package/dist/editors/tiptap/toolbar/AlignCenterButton.svelte +18 -0
  51. package/dist/editors/tiptap/toolbar/AlignCenterButton.svelte.d.ts +7 -0
  52. package/dist/editors/tiptap/toolbar/AlignJustifyButton.svelte +18 -0
  53. package/dist/editors/tiptap/toolbar/AlignJustifyButton.svelte.d.ts +7 -0
  54. package/dist/editors/tiptap/toolbar/AlignLeftButton.svelte +18 -0
  55. package/dist/editors/tiptap/toolbar/AlignLeftButton.svelte.d.ts +7 -0
  56. package/dist/editors/tiptap/toolbar/AlignRightButton.svelte +18 -0
  57. package/dist/editors/tiptap/toolbar/AlignRightButton.svelte.d.ts +7 -0
  58. package/dist/editors/tiptap/toolbar/BoldButton.svelte +18 -0
  59. package/dist/editors/tiptap/toolbar/BoldButton.svelte.d.ts +7 -0
  60. package/dist/editors/tiptap/toolbar/BulletListButton.svelte +18 -0
  61. package/dist/editors/tiptap/toolbar/BulletListButton.svelte.d.ts +7 -0
  62. package/dist/editors/tiptap/toolbar/CodeBlockButton.svelte +18 -0
  63. package/dist/editors/tiptap/toolbar/CodeBlockButton.svelte.d.ts +7 -0
  64. package/dist/editors/tiptap/toolbar/CodeButton.svelte +18 -0
  65. package/dist/editors/tiptap/toolbar/CodeButton.svelte.d.ts +7 -0
  66. package/dist/editors/tiptap/toolbar/ColorButton.svelte +299 -0
  67. package/dist/editors/tiptap/toolbar/ColorButton.svelte.d.ts +20 -0
  68. package/dist/editors/tiptap/toolbar/DocumentButton.svelte +58 -0
  69. package/dist/editors/tiptap/toolbar/DocumentButton.svelte.d.ts +9 -0
  70. package/dist/editors/tiptap/toolbar/HeadingButton.svelte +30 -0
  71. package/dist/editors/tiptap/toolbar/HeadingButton.svelte.d.ts +8 -0
  72. package/dist/editors/tiptap/toolbar/HtmlButton.svelte +68 -0
  73. package/dist/editors/tiptap/toolbar/HtmlButton.svelte.d.ts +7 -0
  74. package/dist/editors/tiptap/toolbar/ImageButton.svelte +54 -0
  75. package/dist/editors/tiptap/toolbar/ImageButton.svelte.d.ts +8 -0
  76. package/dist/editors/tiptap/toolbar/ItalicButton.svelte +18 -0
  77. package/dist/editors/tiptap/toolbar/ItalicButton.svelte.d.ts +7 -0
  78. package/dist/editors/tiptap/toolbar/LinkButton.svelte +257 -0
  79. package/dist/editors/tiptap/toolbar/LinkButton.svelte.d.ts +7 -0
  80. package/dist/editors/tiptap/toolbar/OrderedListButton.svelte +18 -0
  81. package/dist/editors/tiptap/toolbar/OrderedListButton.svelte.d.ts +7 -0
  82. package/dist/editors/tiptap/toolbar/RedoButton.svelte +18 -0
  83. package/dist/editors/tiptap/toolbar/RedoButton.svelte.d.ts +7 -0
  84. package/dist/editors/tiptap/toolbar/StrikethroughButton.svelte +18 -0
  85. package/dist/editors/tiptap/toolbar/StrikethroughButton.svelte.d.ts +7 -0
  86. package/dist/editors/tiptap/toolbar/SubscriptButton.svelte +18 -0
  87. package/dist/editors/tiptap/toolbar/SubscriptButton.svelte.d.ts +7 -0
  88. package/dist/editors/tiptap/toolbar/SuperscriptButton.svelte +18 -0
  89. package/dist/editors/tiptap/toolbar/SuperscriptButton.svelte.d.ts +7 -0
  90. package/dist/editors/tiptap/toolbar/TableButton.svelte +258 -0
  91. package/dist/editors/tiptap/toolbar/TableButton.svelte.d.ts +7 -0
  92. package/dist/editors/tiptap/toolbar/ToolbarButton.svelte +84 -0
  93. package/dist/editors/tiptap/toolbar/ToolbarButton.svelte.d.ts +10 -0
  94. package/dist/editors/tiptap/toolbar/UnderlineButton.svelte +18 -0
  95. package/dist/editors/tiptap/toolbar/UnderlineButton.svelte.d.ts +7 -0
  96. package/dist/editors/tiptap/toolbar/UndoButton.svelte +18 -0
  97. package/dist/editors/tiptap/toolbar/UndoButton.svelte.d.ts +7 -0
  98. package/dist/form/Autocomplete.svelte +86 -135
  99. package/dist/form/Autocomplete.svelte.d.ts +6 -8
  100. package/dist/form/AutocompleteMulti.svelte +385 -227
  101. package/dist/form/AutocompleteMulti.svelte.d.ts +59 -10
  102. package/dist/form/Checkbox.svelte +59 -54
  103. package/dist/form/Checkbox.svelte.d.ts +14 -5
  104. package/dist/form/Chips.svelte +29 -13
  105. package/dist/form/Chips.svelte.d.ts +16 -2
  106. package/dist/form/ComboBox.svelte +30 -20
  107. package/dist/form/ComboBox.svelte.d.ts +1 -1
  108. package/dist/form/ComboBoxItemBuilder.svelte +161 -188
  109. package/dist/form/ComboBoxItemBuilder.svelte.d.ts +19 -2
  110. package/dist/form/ComboBoxMulti.svelte +38 -24
  111. package/dist/form/ComboBoxMulti.svelte.d.ts +1 -1
  112. package/dist/form/CronBuilder.svelte +84 -67
  113. package/dist/form/CronBuilder.svelte.d.ts +16 -3
  114. package/dist/form/DatePicker.svelte +148 -195
  115. package/dist/form/DateRangePicker.svelte +101 -98
  116. package/dist/form/DateTimePicker.svelte +167 -208
  117. package/dist/form/DateTimePicker.svelte.d.ts +10 -2
  118. package/dist/form/FormGroup.svelte +33 -10
  119. package/dist/form/FormGroup.svelte.d.ts +12 -2
  120. package/dist/form/Number.svelte +70 -47
  121. package/dist/form/Number.svelte.d.ts +36 -6
  122. package/dist/form/Radio.svelte +18 -18
  123. package/dist/form/RadioGroup.svelte +23 -12
  124. package/dist/form/RadioGroup.svelte.d.ts +13 -2
  125. package/dist/form/SegmentedControl.svelte +76 -56
  126. package/dist/form/SegmentedControl.svelte.d.ts +9 -4
  127. package/dist/form/Select.svelte +150 -233
  128. package/dist/form/Select.svelte.d.ts +29 -5
  129. package/dist/form/SelectMulti.svelte +163 -277
  130. package/dist/form/SelectMulti.svelte.d.ts +36 -7
  131. package/dist/form/Slider.svelte +183 -269
  132. package/dist/form/Slider.svelte.d.ts +32 -17
  133. package/dist/form/StringArrayBuilder.svelte +249 -0
  134. package/dist/form/StringArrayBuilder.svelte.d.ts +15 -0
  135. package/dist/form/Switch.svelte +164 -106
  136. package/dist/form/Switch.svelte.d.ts +22 -3
  137. package/dist/form/TextArea.svelte +49 -29
  138. package/dist/form/TextArea.svelte.d.ts +23 -3
  139. package/dist/form/Textbox.svelte +69 -68
  140. package/dist/form/Textbox.svelte.d.ts +32 -4
  141. package/dist/form/TimePicker.svelte +42 -47
  142. package/dist/form/TimePicker.svelte.d.ts +12 -2
  143. package/dist/form/comboBoxCore.svelte.d.ts +99 -0
  144. package/dist/form/comboBoxCore.svelte.js +243 -0
  145. package/dist/icon/Icon.svelte +8 -3
  146. package/dist/icon/Icon.svelte.d.ts +8 -3
  147. package/dist/icon/file-type-bmp.svg +1 -0
  148. package/dist/icon/file-type-csv.svg +1 -0
  149. package/dist/icon/file-type-doc.svg +1 -0
  150. package/dist/icon/file-type-docx.svg +1 -0
  151. package/dist/icon/file-type-jpg.svg +1 -0
  152. package/dist/icon/file-type-pdf.svg +1 -0
  153. package/dist/icon/file-type-png.svg +1 -0
  154. package/dist/icon/file-type-ppt.svg +1 -0
  155. package/dist/icon/file-type-svg.svg +1 -0
  156. package/dist/icon/file-type-txt.svg +1 -0
  157. package/dist/icon/file-type-xls.svg +1 -0
  158. package/dist/icon/file-type-zip.svg +1 -0
  159. package/dist/icon/index.d.ts +166 -151
  160. package/dist/icon/index.js +166 -152
  161. package/dist/icon/logo-placeholder.svg +6 -0
  162. package/dist/icon/source-code.svg +1 -0
  163. package/dist/icon/sun-moon.svg +1 -0
  164. package/dist/icon/table.svg +6 -0
  165. package/dist/index.d.ts +87 -26
  166. package/dist/index.js +25 -28
  167. package/dist/layout/AppShell.svelte +12 -162
  168. package/dist/layout/AppShell.svelte.d.ts +6 -27
  169. package/dist/layout/CustomNavbar.svelte +9 -7
  170. package/dist/layout/CustomNavbar.svelte.d.ts +4 -2
  171. package/dist/layout/Navbar.svelte +161 -129
  172. package/dist/layout/Navbar.svelte.d.ts +29 -15
  173. package/dist/layout/NavbarItemDisplay.svelte +2 -2
  174. package/dist/layout/NavbarItemView.svelte +182 -0
  175. package/dist/layout/NavbarItemView.svelte.d.ts +10 -0
  176. package/dist/layout/Sidenav.svelte +280 -341
  177. package/dist/layout/Sidenav.svelte.d.ts +36 -4
  178. package/dist/models/ComboBoxItem.d.ts +2 -0
  179. package/dist/models/Employee.d.ts +53 -0
  180. package/dist/models/Employee.js +23 -0
  181. package/dist/models/Hyperlink.d.ts +3 -1
  182. package/dist/models/LinkCollectionItem.d.ts +3 -1
  183. package/dist/models/NavbarItem.d.ts +6 -2
  184. package/dist/theme.svelte.d.ts +0 -1
  185. package/dist/theme.svelte.js +46 -58
  186. package/dist/ui/Accordion.svelte +81 -242
  187. package/dist/ui/Accordion.svelte.d.ts +37 -14
  188. package/dist/ui/AccordionItem.svelte +303 -0
  189. package/dist/ui/AccordionItem.svelte.d.ts +21 -0
  190. package/dist/ui/ActionIcon.svelte +25 -21
  191. package/dist/ui/ActionIcon.svelte.d.ts +15 -2
  192. package/dist/ui/Badge.svelte +163 -171
  193. package/dist/ui/Badge.svelte.d.ts +13 -5
  194. package/dist/ui/Button.svelte +178 -205
  195. package/dist/ui/Button.svelte.d.ts +19 -2
  196. package/dist/ui/ButtonVariant.d.ts +15 -1
  197. package/dist/ui/ContextMenu.svelte +146 -0
  198. package/dist/ui/ContextMenu.svelte.d.ts +37 -0
  199. package/dist/ui/ContextMenuList.svelte +188 -0
  200. package/dist/ui/ContextMenuList.svelte.d.ts +12 -0
  201. package/dist/ui/Dialog.svelte +183 -111
  202. package/dist/ui/Dialog.svelte.d.ts +21 -4
  203. package/dist/ui/Drawer.svelte +237 -184
  204. package/dist/ui/Drawer.svelte.d.ts +20 -2
  205. package/dist/ui/Dropdown.svelte +24 -14
  206. package/dist/ui/Dropdown.svelte.d.ts +11 -2
  207. package/dist/ui/Dropzone.svelte +159 -57
  208. package/dist/ui/Dropzone.svelte.d.ts +29 -2
  209. package/dist/ui/Link.svelte +12 -4
  210. package/dist/ui/Link.svelte.d.ts +8 -2
  211. package/dist/ui/Loader.svelte +23 -18
  212. package/dist/ui/Loader.svelte.d.ts +5 -2
  213. package/dist/ui/Logo.svelte +37 -0
  214. package/dist/ui/Logo.svelte.d.ts +16 -0
  215. package/dist/ui/MultiSortable.svelte +287 -0
  216. package/dist/ui/MultiSortable.svelte.d.ts +50 -0
  217. package/dist/ui/Pagination.svelte +15 -9
  218. package/dist/ui/Pagination.svelte.d.ts +6 -2
  219. package/dist/ui/Popover.svelte +43 -65
  220. package/dist/ui/Popover.svelte.d.ts +14 -5
  221. package/dist/ui/ProgressBar.svelte +28 -30
  222. package/dist/ui/ProgressBarVariant.d.ts +7 -1
  223. package/dist/ui/SegmentedControl.svelte +0 -0
  224. package/dist/ui/SegmentedControl.svelte.d.ts +26 -0
  225. package/dist/ui/Sortable.svelte +163 -0
  226. package/dist/ui/Sortable.svelte.d.ts +47 -0
  227. package/dist/ui/Table.svelte +383 -80
  228. package/dist/ui/Table.svelte.d.ts +43 -2
  229. package/dist/ui/Tabs.svelte +22 -18
  230. package/dist/ui/Tabs.svelte.d.ts +6 -2
  231. package/dist/ui/ThemeSwitcher.svelte +26 -7
  232. package/dist/ui/ThemeSwitcher.svelte.d.ts +4 -2
  233. package/dist/ui/Tooltip.svelte +312 -180
  234. package/dist/ui/Tooltip.svelte.d.ts +4 -3
  235. package/dist/uiTheme.svelte.d.ts +86 -0
  236. package/dist/uiTheme.svelte.js +214 -0
  237. package/dist/util/DateFunctions.js +1 -1
  238. package/dist/util/DragDrop.d.ts +50 -0
  239. package/dist/util/DragDrop.js +154 -0
  240. package/dist/util/NavigateTo.js +2 -2
  241. package/dist/util/dayjs.d.ts +4 -0
  242. package/dist/util/dayjs.js +15 -0
  243. package/package.json +66 -26
  244. package/dist/display/Alert.svelte +0 -179
  245. package/dist/display/Alert.svelte.d.ts +0 -13
  246. package/dist/form/FileInput.svelte +0 -235
  247. package/dist/form/FileInput.svelte.d.ts +0 -23
  248. package/dist/form/PasswordInput.svelte +0 -253
  249. package/dist/form/PasswordInput.svelte.d.ts +0 -34
  250. package/dist/form/Rating.svelte +0 -235
  251. package/dist/form/Rating.svelte.d.ts +0 -21
  252. package/dist/styles/components.css +0 -199
  253. package/dist/styles/dark.css +0 -146
  254. package/dist/styles/index.css +0 -116
  255. package/dist/styles/reset.css +0 -110
  256. package/dist/styles/semantic.css +0 -86
  257. package/dist/styles/tokens.css +0 -203
  258. package/dist/styles/utilities.css +0 -523
  259. package/dist/ui/Breadcrumbs.svelte +0 -131
  260. package/dist/ui/Breadcrumbs.svelte.d.ts +0 -16
  261. package/dist/ui/LoadingOverlay.svelte +0 -53
  262. package/dist/ui/LoadingOverlay.svelte.d.ts +0 -11
  263. package/dist/ui/Progress.svelte +0 -191
  264. package/dist/ui/Progress.svelte.d.ts +0 -15
  265. package/dist/ui/RingProgress.svelte +0 -141
  266. package/dist/ui/RingProgress.svelte.d.ts +0 -18
  267. package/dist/ui/Skeleton.svelte +0 -85
  268. package/dist/ui/Skeleton.svelte.d.ts +0 -12
  269. package/dist/ui/Stepper.svelte +0 -355
  270. package/dist/ui/Stepper.svelte.d.ts +0 -24
  271. package/dist/ui/Timeline.svelte +0 -225
  272. package/dist/ui/Timeline.svelte.d.ts +0 -23
  273. /package/dist/{actions → util}/ClickOutside.d.ts +0 -0
  274. /package/dist/{actions → util}/ClickOutside.js +0 -0
  275. /package/dist/{transitions → util}/Transitions.d.ts +0 -0
  276. /package/dist/{transitions → util}/Transitions.js +0 -0
@@ -39,6 +39,10 @@
39
39
  hideNoResults?: boolean;
40
40
  /** Prevent updating value when an option is selected */
41
41
  preventChangeOnSelection?: boolean;
42
+ /** Allow suggesting a new value be added when the input doesn't match an existing option */
43
+ allowAdd?: boolean;
44
+ /** Builds the label shown for the "add new value" suggestion (default: `Add "<value>"`) */
45
+ addItemLabel?: (value: string) => string;
42
46
  /** Text shown while loading options */
43
47
  loadingText?: string;
44
48
  /** CSS classes for the FormGroup wrapper */
@@ -69,23 +73,17 @@
69
73
  onSelect?: (e: ComboBoxItem) => void;
70
74
  /** Callback when selection changes (returns full item object) */
71
75
  onchangeRaw?: (e: ComboBoxItem | undefined) => void;
72
- /** Allow creating new options not in the list */
73
- allowCreate?: boolean;
74
- /** Show a "no results" message when no options match */
75
- showNoResultsMessage?: boolean;
76
- /** Show required indicator (alias for required) */
77
- showRequired?: boolean;
78
- /** Callback when a new option is created (requires allowCreate) */
79
- onCreate?: (value: string) => void;
76
+ /** Callback when the user chooses to add the typed value as a new item */
77
+ onItemAdded?: (value: string) => void;
80
78
  }
81
79
  </script>
82
80
 
83
81
  <script lang="ts">
84
82
  import ComboBoxMulti from './ComboBoxMulti.svelte';
85
- import { clickOutside } from '../actions/ClickOutside.js';
83
+ import { clickOutside } from '../util/ClickOutside.js';
86
84
  import Textbox from './Textbox.svelte';
87
- import type { NotifyModel } from '../models/NotifyModel.js';
88
- import { onMount, tick } from 'svelte';
85
+ import { ComboBoxCore, findItemByValue } from './comboBoxCore.svelte.js';
86
+ import { tick } from 'svelte';
89
87
  import { useDialogEvents } from '../ui/DialogEvents.svelte.js';
90
88
 
91
89
  let {
@@ -104,6 +102,8 @@
104
102
  autofocusDialog = false,
105
103
  hideNoResults = false,
106
104
  preventChangeOnSelection = false,
105
+ allowAdd = false,
106
+ addItemLabel = (v: string) => `Add "${v}"`,
107
107
  loadingText = '',
108
108
  groupClass = '',
109
109
  leftIconSvg,
@@ -119,40 +119,51 @@
119
119
  enterPressed = undefined,
120
120
  onSelect = undefined,
121
121
  onchangeRaw = undefined,
122
- allowCreate = false,
123
- showNoResultsMessage = false,
124
- showRequired = false,
125
- onCreate = undefined
122
+ onItemAdded = undefined
126
123
  }: AutocompleteProps = $props();
127
124
 
128
- let preloading = $state(false);
129
- let searching = $state(false);
130
- let timeout: number;
125
+ const core = new ComboBoxCore({
126
+ getOptions: () => options,
127
+ getGroupedOptions: () => groupedOptions,
128
+ getValue: () => value,
129
+ setValue: (v) => (value = v ?? ''),
130
+ setRawValue: (r) => (rawValue = r),
131
+ getFetchFunction: () => fetchFunction,
132
+ getSearchFunction: () => searchFunction,
133
+ getRetrieveLabelFunction: () => retrieveLabelFunction,
134
+ clearUnknownStatic: false,
135
+ onOptionsChanged: () => {
136
+ if (value) core.filterLocal(value);
137
+ }
138
+ });
131
139
 
132
- let allGroups: ComboBoxGroup[] = $state([]);
133
- let filteredGroups: ComboBoxGroup[] = $state([]);
140
+ /** Synthetic "add new value" suggestion shown when the typed value matches no option */
141
+ let addOption: ComboBoxItem | undefined = $derived.by(() => {
142
+ const trimmed = value?.trim();
143
+ if (!allowAdd || !trimmed) return undefined;
144
+
145
+ const exists = core.allGroups
146
+ .flatMap((x) => x.items)
147
+ .some(
148
+ (x) =>
149
+ x.label.toLowerCase() === trimmed.toLowerCase() ||
150
+ x.value.toLowerCase() === trimmed.toLowerCase()
151
+ );
152
+ if (exists) return undefined;
153
+
154
+ return { label: addItemLabel(trimmed), value: trimmed, isAddNew: true };
155
+ });
156
+
157
+ /** Groups passed to the dropdown, including the add suggestion when applicable */
158
+ let displayGroups: ComboBoxGroup[] = $derived(
159
+ addOption
160
+ ? [...core.filteredGroups, { label: '', items: [addOption], showGroupName: false }]
161
+ : core.filteredGroups
162
+ );
134
163
 
135
164
  let open = $state(false);
136
165
  let internalValue = $state(value);
137
166
 
138
- onMount(() => {
139
- if (fetchFunction) {
140
- preloading = true;
141
- fetchFunction().then((response: NotifyModel<ComboBoxItem[]>) => {
142
- convertOptions(response.object!);
143
- preloadValues();
144
- preloading = false;
145
- });
146
- } else {
147
- if (groupedOptions.length) {
148
- convertGroupOptions(groupedOptions);
149
- } else if (options.length) {
150
- convertOptions(options);
151
- }
152
- preloadValues();
153
- }
154
- });
155
-
156
167
  useDialogEvents({
157
168
  onFirstOpen: () => {
158
169
  if (autofocus) {
@@ -178,76 +189,28 @@
178
189
  $effect(() => {
179
190
  if (value !== internalValue) {
180
191
  internalValue = value;
181
- rawValue =
182
- allGroups.flatMap((x) => x.items).find((x) => x.value === value) ?? undefined;
192
+ rawValue = findItemByValue(core.allGroups, value);
183
193
  onchangeRaw?.(rawValue);
184
- preloadValues();
194
+ core.preloadValues();
185
195
  }
186
196
  });
187
197
 
188
- function preloadValues() {
189
- if (!value) {
190
- rawValue = undefined;
191
- return;
192
- }
193
-
194
- const foundOption = allGroups.flatMap((x) => x.items).find((x) => x.value === value);
195
-
196
- if (foundOption !== undefined) {
197
- rawValue = foundOption;
198
- } else if (searchFunction && retrieveLabelFunction) {
199
- preloading = true;
200
- retrieveLabelFunction(value).then((response) => {
201
- rawValue = {
202
- label: response.object ?? value!.toString(),
203
- value: value!
204
- };
205
- preloading = false;
206
- });
207
- }
208
- }
209
-
210
- function convertOptions(opts: ComboBoxItem[]) {
211
- const allOptions = opts.map((option) => ({
212
- ...option,
213
- selected: option.value === value
214
- }));
215
- allGroups = [{ label: '', items: [...allOptions] }];
216
- filteredGroups = [{ label: '', items: [...allOptions] }];
217
- }
218
-
219
- function convertGroupOptions(groups: ComboBoxGroup[]) {
220
- allGroups = groups.map((group) => ({
221
- ...group,
222
- items: group.items.map((option) => ({
223
- ...option,
224
- selected: option.value === value,
225
- groupName: group.label
226
- }))
227
- }));
228
- filteredGroups = [...allGroups];
229
- }
230
-
231
198
  let selectionJustMade = false;
232
199
 
233
200
  function onSelection(selectedValue: ComboBoxItem) {
234
201
  selectionJustMade = true;
235
202
  open = false;
236
203
 
237
- // Handle "Create" items from allowCreate
238
- if (allowCreate && selectedValue.label.startsWith('Create "')) {
239
- const created = selectedValue.value;
240
- value = created;
241
- internalValue = value;
242
- rawValue = { value: created, label: created };
243
- onCreate?.(created);
244
- onchangeRaw?.(rawValue);
204
+ if (selectedValue.isAddNew) {
205
+ addItem(selectedValue.value);
245
206
  return;
246
207
  }
247
208
 
248
- allGroups.flatMap((x) => x.items).forEach((option) => {
249
- option.selected = option.value === selectedValue.value;
250
- });
209
+ core.allGroups
210
+ .flatMap((x) => x.items)
211
+ .forEach((option) => {
212
+ option.selected = option.value === selectedValue.value;
213
+ });
251
214
 
252
215
  if (!preventChangeOnSelection) {
253
216
  value = selectedValue.value;
@@ -260,48 +223,36 @@
260
223
  onchangeRaw?.(selectedValue);
261
224
  }
262
225
 
226
+ function addItem(newValue: string) {
227
+ open = false;
228
+
229
+ const newItem: ComboBoxItem = { label: newValue, value: newValue };
230
+
231
+ if (!preventChangeOnSelection) {
232
+ value = newValue;
233
+ internalValue = value;
234
+ }
235
+
236
+ rawValue = newItem;
237
+
238
+ onItemAdded?.(newValue);
239
+ onchangeRaw?.(newItem);
240
+ }
241
+
263
242
  function onFilterChange(filterValue: string) {
264
243
  if (filterValue.length === 0) {
265
- filteredGroups = allGroups;
244
+ core.filterLocal('');
266
245
  open = true;
267
246
  return;
268
247
  }
269
248
 
270
249
  if (searchFunction && filterValue) {
271
- clearTimeout(timeout);
272
- searching = true;
273
- timeout = window.setTimeout(() => {
274
- searchFunction(filterValue).then((response: NotifyModel<ComboBoxItem[]>) => {
275
- convertOptions(response.object!);
276
- searching = false;
277
- open = true;
278
- });
279
- }, 300);
280
- } else if (allGroups.length) {
281
- filteredGroups = allGroups
282
- .map((group) => ({
283
- ...group,
284
- items: group.items.filter((x) =>
285
- x.label.toLowerCase().includes(filterValue.toLowerCase())
286
- )
287
- }))
288
- .filter((group) => group.items.length > 0);
250
+ core.search(filterValue, () => (open = true));
251
+ } else {
252
+ core.filterLocal(filterValue);
289
253
  open = true;
290
254
  }
291
255
 
292
- if (allowCreate && filterValue) {
293
- const hasExact = filteredGroups
294
- .flatMap((g) => g.items)
295
- .some((x) => x.label.toLowerCase() === filterValue.toLowerCase());
296
- if (!hasExact) {
297
- const createItem: ComboBoxItem = { value: filterValue, label: `Create "${filterValue}"` };
298
- filteredGroups = [
299
- ...filteredGroups,
300
- { label: '', items: [createItem] }
301
- ];
302
- }
303
- }
304
-
305
256
  onchange?.(filterValue);
306
257
  }
307
258
 
@@ -345,16 +296,16 @@
345
296
  {label}
346
297
  class={classes}
347
298
  {containerClass}
348
- required={required || showRequired}
299
+ {required}
349
300
  {showError}
350
301
  {errorText}
351
302
  {tooltipLocation}
352
303
  {tooltipContent}
353
304
  {tooltipText}
354
305
  bind:textboxElement
355
- placeholder={preloading ? 'Loading...' : placeholder}
356
- loading={searching || preloading}
357
- disabled={preloading || disabled}
306
+ placeholder={core.preloading ? 'Loading...' : placeholder}
307
+ loading={core.searching || core.preloading}
308
+ disabled={core.preloading || disabled}
358
309
  autocomplete="off"
359
310
  {groupClass}
360
311
  {leftIconSvg}
@@ -371,11 +322,11 @@
371
322
  bind:this={comboBoxEl}
372
323
  filterString={value}
373
324
  values={rawValue ? [rawValue] : []}
374
- onSelection={onSelection}
375
- groupedOptions={filteredGroups}
325
+ {onSelection}
326
+ groupedOptions={displayGroups}
376
327
  {open}
377
- loading={searching}
378
- showNoResultsMessage={showNoResultsMessage || !hideNoResults}
328
+ loading={core.searching}
329
+ {hideNoResults}
379
330
  {loadingText}
380
331
  />
381
332
  </div>
@@ -31,6 +31,10 @@ export interface AutocompleteProps {
31
31
  hideNoResults?: boolean;
32
32
  /** Prevent updating value when an option is selected */
33
33
  preventChangeOnSelection?: boolean;
34
+ /** Allow suggesting a new value be added when the input doesn't match an existing option */
35
+ allowAdd?: boolean;
36
+ /** Builds the label shown for the "add new value" suggestion (default: `Add "<value>"`) */
37
+ addItemLabel?: (value: string) => string;
34
38
  /** Text shown while loading options */
35
39
  loadingText?: string;
36
40
  /** CSS classes for the FormGroup wrapper */
@@ -61,14 +65,8 @@ export interface AutocompleteProps {
61
65
  onSelect?: (e: ComboBoxItem) => void;
62
66
  /** Callback when selection changes (returns full item object) */
63
67
  onchangeRaw?: (e: ComboBoxItem | undefined) => void;
64
- /** Allow creating new options not in the list */
65
- allowCreate?: boolean;
66
- /** Show a "no results" message when no options match */
67
- showNoResultsMessage?: boolean;
68
- /** Show required indicator (alias for required) */
69
- showRequired?: boolean;
70
- /** Callback when a new option is created (requires allowCreate) */
71
- onCreate?: (value: string) => void;
68
+ /** Callback when the user chooses to add the typed value as a new item */
69
+ onItemAdded?: (value: string) => void;
72
70
  }
73
71
  declare const Autocomplete: import("svelte").Component<AutocompleteProps, {}, "value" | "rawValue">;
74
72
  type Autocomplete = ReturnType<typeof Autocomplete>;