@placeholderco/placeholder-ui 1.0.11 → 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 (289) 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 +270 -137
  99. package/dist/form/Autocomplete.svelte.d.ts +58 -10
  100. package/dist/form/AutocompleteMulti.svelte +385 -227
  101. package/dist/form/AutocompleteMulti.svelte.d.ts +59 -10
  102. package/dist/form/Checkbox.svelte +124 -43
  103. package/dist/form/Checkbox.svelte.d.ts +26 -2
  104. package/dist/form/Chips.svelte +47 -17
  105. package/dist/form/Chips.svelte.d.ts +24 -3
  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 +177 -191
  115. package/dist/form/DatePicker.svelte.d.ts +17 -2
  116. package/dist/form/DateRangePicker.svelte +775 -0
  117. package/dist/form/DateRangePicker.svelte.d.ts +23 -0
  118. package/dist/form/DateTimePicker.svelte +168 -209
  119. package/dist/form/DateTimePicker.svelte.d.ts +10 -2
  120. package/dist/form/FormGroup.svelte +33 -10
  121. package/dist/form/FormGroup.svelte.d.ts +12 -2
  122. package/dist/form/Number.svelte +71 -29
  123. package/dist/form/Number.svelte.d.ts +39 -6
  124. package/dist/form/Radio.svelte +174 -0
  125. package/dist/form/Radio.svelte.d.ts +21 -0
  126. package/dist/form/RadioGroup.svelte +52 -138
  127. package/dist/form/RadioGroup.svelte.d.ts +19 -2
  128. package/dist/form/SegmentedControl.svelte +103 -57
  129. package/dist/form/SegmentedControl.svelte.d.ts +12 -2
  130. package/dist/form/Select.svelte +160 -229
  131. package/dist/form/Select.svelte.d.ts +35 -6
  132. package/dist/form/SelectMulti.svelte +166 -277
  133. package/dist/form/SelectMulti.svelte.d.ts +37 -6
  134. package/dist/form/Slider.svelte +185 -268
  135. package/dist/form/Slider.svelte.d.ts +33 -16
  136. package/dist/form/StringArrayBuilder.svelte +249 -0
  137. package/dist/form/StringArrayBuilder.svelte.d.ts +15 -0
  138. package/dist/form/Switch.svelte +164 -106
  139. package/dist/form/Switch.svelte.d.ts +22 -3
  140. package/dist/form/TextArea.svelte +80 -45
  141. package/dist/form/TextArea.svelte.d.ts +35 -10
  142. package/dist/form/Textbox.svelte +80 -47
  143. package/dist/form/Textbox.svelte.d.ts +41 -8
  144. package/dist/form/TimePicker.svelte +42 -47
  145. package/dist/form/TimePicker.svelte.d.ts +12 -2
  146. package/dist/form/comboBoxCore.svelte.d.ts +99 -0
  147. package/dist/form/comboBoxCore.svelte.js +243 -0
  148. package/dist/icon/Icon.svelte +8 -3
  149. package/dist/icon/Icon.svelte.d.ts +8 -3
  150. package/dist/icon/cube-send.svg +1 -0
  151. package/dist/icon/file-type-bmp.svg +1 -0
  152. package/dist/icon/file-type-csv.svg +1 -0
  153. package/dist/icon/file-type-doc.svg +1 -0
  154. package/dist/icon/file-type-docx.svg +1 -0
  155. package/dist/icon/file-type-jpg.svg +1 -0
  156. package/dist/icon/file-type-pdf.svg +1 -0
  157. package/dist/icon/file-type-png.svg +1 -0
  158. package/dist/icon/file-type-ppt.svg +1 -0
  159. package/dist/icon/file-type-svg.svg +1 -0
  160. package/dist/icon/file-type-txt.svg +1 -0
  161. package/dist/icon/file-type-xls.svg +1 -0
  162. package/dist/icon/file-type-zip.svg +1 -0
  163. package/dist/icon/index.d.ts +166 -145
  164. package/dist/icon/index.js +166 -146
  165. package/dist/icon/layout-sidebar-left-collapse.svg +1 -0
  166. package/dist/icon/layout-sidebar-left-expand.svg +1 -0
  167. package/dist/icon/logo-placeholder.svg +6 -0
  168. package/dist/icon/paperclip.svg +1 -0
  169. package/dist/icon/source-code.svg +1 -0
  170. package/dist/icon/sun-moon.svg +1 -0
  171. package/dist/icon/table.svg +6 -0
  172. package/dist/icon/thumb-down.svg +1 -0
  173. package/dist/icon/thumb-up.svg +1 -0
  174. package/dist/index.d.ts +93 -22
  175. package/dist/index.js +28 -27
  176. package/dist/layout/AppShell.svelte +12 -162
  177. package/dist/layout/AppShell.svelte.d.ts +6 -27
  178. package/dist/layout/CustomNavbar.svelte +9 -7
  179. package/dist/layout/CustomNavbar.svelte.d.ts +4 -2
  180. package/dist/layout/Navbar.svelte +158 -110
  181. package/dist/layout/Navbar.svelte.d.ts +26 -12
  182. package/dist/layout/NavbarItemDisplay.svelte +2 -2
  183. package/dist/layout/NavbarItemView.svelte +182 -0
  184. package/dist/layout/NavbarItemView.svelte.d.ts +10 -0
  185. package/dist/layout/Sidenav.svelte +280 -341
  186. package/dist/layout/Sidenav.svelte.d.ts +36 -4
  187. package/dist/models/ComboBoxItem.d.ts +2 -0
  188. package/dist/models/Employee.d.ts +53 -0
  189. package/dist/models/Employee.js +23 -0
  190. package/dist/models/Hyperlink.d.ts +3 -1
  191. package/dist/models/LinkCollectionItem.d.ts +3 -1
  192. package/dist/models/NavbarItem.d.ts +6 -2
  193. package/dist/theme.svelte.d.ts +0 -1
  194. package/dist/theme.svelte.js +46 -58
  195. package/dist/ui/Accordion.svelte +81 -242
  196. package/dist/ui/Accordion.svelte.d.ts +37 -14
  197. package/dist/ui/AccordionItem.svelte +303 -0
  198. package/dist/ui/AccordionItem.svelte.d.ts +21 -0
  199. package/dist/ui/ActionIcon.svelte +25 -21
  200. package/dist/ui/ActionIcon.svelte.d.ts +15 -2
  201. package/dist/ui/Badge.svelte +170 -161
  202. package/dist/ui/Badge.svelte.d.ts +16 -4
  203. package/dist/ui/Button.svelte +178 -205
  204. package/dist/ui/Button.svelte.d.ts +19 -2
  205. package/dist/ui/ButtonVariant.d.ts +15 -1
  206. package/dist/ui/ContextMenu.svelte +146 -0
  207. package/dist/ui/ContextMenu.svelte.d.ts +37 -0
  208. package/dist/ui/ContextMenuList.svelte +188 -0
  209. package/dist/ui/ContextMenuList.svelte.d.ts +12 -0
  210. package/dist/ui/Dialog.svelte +183 -104
  211. package/dist/ui/Dialog.svelte.d.ts +21 -2
  212. package/dist/ui/Drawer.svelte +237 -184
  213. package/dist/ui/Drawer.svelte.d.ts +20 -2
  214. package/dist/ui/Dropdown.svelte +24 -14
  215. package/dist/ui/Dropdown.svelte.d.ts +11 -2
  216. package/dist/ui/Dropzone.svelte +159 -57
  217. package/dist/ui/Dropzone.svelte.d.ts +29 -2
  218. package/dist/ui/Link.svelte +12 -4
  219. package/dist/ui/Link.svelte.d.ts +8 -2
  220. package/dist/ui/Loader.svelte +23 -18
  221. package/dist/ui/Loader.svelte.d.ts +5 -2
  222. package/dist/ui/Logo.svelte +37 -0
  223. package/dist/ui/Logo.svelte.d.ts +16 -0
  224. package/dist/ui/MultiSortable.svelte +287 -0
  225. package/dist/ui/MultiSortable.svelte.d.ts +50 -0
  226. package/dist/ui/Pagination.svelte +12 -6
  227. package/dist/ui/Pagination.svelte.d.ts +6 -2
  228. package/dist/ui/Popover.svelte +43 -65
  229. package/dist/ui/Popover.svelte.d.ts +14 -5
  230. package/dist/ui/ProgressBar.svelte +169 -0
  231. package/dist/ui/ProgressBar.svelte.d.ts +30 -0
  232. package/dist/ui/ProgressBarVariant.d.ts +7 -0
  233. package/dist/ui/ProgressBarVariant.js +1 -0
  234. package/dist/ui/SegmentedControl.svelte +0 -0
  235. package/dist/ui/SegmentedControl.svelte.d.ts +26 -0
  236. package/dist/ui/Sortable.svelte +163 -0
  237. package/dist/ui/Sortable.svelte.d.ts +47 -0
  238. package/dist/ui/Table.svelte +497 -56
  239. package/dist/ui/Table.svelte.d.ts +64 -2
  240. package/dist/ui/Tabs.svelte +22 -18
  241. package/dist/ui/Tabs.svelte.d.ts +6 -2
  242. package/dist/ui/ThemeSwitcher.svelte +26 -7
  243. package/dist/ui/ThemeSwitcher.svelte.d.ts +4 -2
  244. package/dist/ui/Tooltip.svelte +312 -180
  245. package/dist/ui/Tooltip.svelte.d.ts +4 -3
  246. package/dist/uiTheme.svelte.d.ts +86 -0
  247. package/dist/uiTheme.svelte.js +214 -0
  248. package/dist/util/DateFunctions.js +1 -1
  249. package/dist/util/DragDrop.d.ts +50 -0
  250. package/dist/util/DragDrop.js +154 -0
  251. package/dist/util/NavigateTo.js +2 -2
  252. package/dist/util/dayjs.d.ts +4 -0
  253. package/dist/util/dayjs.js +15 -0
  254. package/dist/util/interceptLinkClick.d.ts +13 -0
  255. package/dist/util/interceptLinkClick.js +33 -0
  256. package/package.json +66 -26
  257. package/dist/display/Alert.svelte +0 -179
  258. package/dist/display/Alert.svelte.d.ts +0 -13
  259. package/dist/form/FileInput.svelte +0 -235
  260. package/dist/form/FileInput.svelte.d.ts +0 -23
  261. package/dist/form/PasswordInput.svelte +0 -252
  262. package/dist/form/PasswordInput.svelte.d.ts +0 -33
  263. package/dist/form/Rating.svelte +0 -235
  264. package/dist/form/Rating.svelte.d.ts +0 -21
  265. package/dist/styles/components.css +0 -199
  266. package/dist/styles/dark.css +0 -146
  267. package/dist/styles/index.css +0 -116
  268. package/dist/styles/reset.css +0 -110
  269. package/dist/styles/semantic.css +0 -86
  270. package/dist/styles/tokens.css +0 -203
  271. package/dist/styles/utilities.css +0 -523
  272. package/dist/ui/Breadcrumbs.svelte +0 -131
  273. package/dist/ui/Breadcrumbs.svelte.d.ts +0 -16
  274. package/dist/ui/LoadingOverlay.svelte +0 -53
  275. package/dist/ui/LoadingOverlay.svelte.d.ts +0 -11
  276. package/dist/ui/Progress.svelte +0 -191
  277. package/dist/ui/Progress.svelte.d.ts +0 -15
  278. package/dist/ui/RingProgress.svelte +0 -141
  279. package/dist/ui/RingProgress.svelte.d.ts +0 -18
  280. package/dist/ui/Skeleton.svelte +0 -85
  281. package/dist/ui/Skeleton.svelte.d.ts +0 -12
  282. package/dist/ui/Stepper.svelte +0 -355
  283. package/dist/ui/Stepper.svelte.d.ts +0 -24
  284. package/dist/ui/Timeline.svelte +0 -225
  285. package/dist/ui/Timeline.svelte.d.ts +0 -23
  286. /package/dist/{actions → util}/ClickOutside.d.ts +0 -0
  287. /package/dist/{actions → util}/ClickOutside.js +0 -0
  288. /package/dist/{transitions → util}/Transitions.d.ts +0 -0
  289. /package/dist/{transitions → util}/Transitions.js +0 -0
@@ -1,70 +1,102 @@
1
1
  <script lang="ts">
2
- import { clickOutside } from "../actions/ClickOutside.js";
3
- import type { NotifyModel } from "../models/NotifyModel.js";
2
+ import { clickOutside } from '../util/ClickOutside.js';
4
3
  import type {
5
4
  ComboBoxGroup,
6
5
  ComboBoxItem,
7
6
  FetchFunctionType,
8
7
  RetrieveLabelFunctionType,
9
- SearchFunctionType,
10
- } from "../models/ComboBoxItem.js";
11
- import ComboBoxMulti from "./ComboBoxMulti.svelte";
12
- import FormGroup from "./FormGroup.svelte";
13
- import Icon from "../icon/Icon.svelte";
14
- import Loader from "../ui/Loader.svelte";
15
- import { useDialogEvents } from "../ui/DialogEvents.svelte.js";
16
- import selectorSvg from "../icon/selector.svg?raw";
17
- import { iconX, iconCopy } from "../icon/index.js";
18
- import ActionIcon from "../ui/ActionIcon.svelte";
19
- import { onMount, tick, type Snippet } from "svelte";
20
-
21
- interface Props {
8
+ SearchFunctionType
9
+ } from '../models/ComboBoxItem.js';
10
+ import { ComboBoxCore } from './comboBoxCore.svelte.js';
11
+ import ComboBoxMulti from './ComboBoxMulti.svelte';
12
+ import FormGroup from './FormGroup.svelte';
13
+ import Icon from '../icon/Icon.svelte';
14
+ import Loader from '../ui/Loader.svelte';
15
+ import { useDialogEvents } from '../ui/DialogEvents.svelte.js';
16
+ import selectorSvg from '../icon/selector.svg?raw';
17
+ import { iconX, iconCopy } from '../icon/index.js';
18
+ import ActionIcon from '../ui/ActionIcon.svelte';
19
+ import { onMount, tick, type Snippet } from 'svelte';
20
+
21
+ const autoName = `select-${crypto.randomUUID()}`;
22
+
23
+ export interface SelectProps {
24
+ /** HTML name attribute for the select (falls back to label, then auto-generated) */
25
+ name?: string;
26
+ /** Label text displayed above the select */
22
27
  label?: string;
28
+ /** Selected value (bindable) */
23
29
  value?: string;
30
+ /** Full selected item object */
24
31
  rawValue?: ComboBoxItem;
32
+ /** Placeholder text when no value is selected */
25
33
  placeholder?: string;
34
+ /** CSS classes for the select element */
26
35
  class?: string;
36
+ /** CSS classes for the container element */
27
37
  containerClass?: string;
38
+ /** Disable the select */
28
39
  disabled?: boolean;
40
+ /** Mark field as required (shows asterisk) */
29
41
  required?: boolean;
42
+ /** Show error state styling */
30
43
  showError?: boolean;
44
+ /** Error message to display */
31
45
  errorText?: string;
32
- autofocus?: boolean; // will also cause dialog autofocus on first open only
33
- autofocusDialog?: boolean; // will cause autofocus on every open, not just the first time
46
+ /** Auto-focus on mount (first dialog open only) */
47
+ autofocus?: boolean;
48
+ /** Auto-focus on every dialog open */
49
+ autofocusDialog?: boolean;
50
+ /** Enable search/filter within options */
34
51
  allowSearch?: boolean;
35
- showNoResultsMessage?: boolean;
52
+ /** Hide "no results" message when search finds nothing */
53
+ hideNoResults?: boolean;
54
+ /** Text shown while loading options */
36
55
  loadingText?: string;
56
+ /** Flat list of selectable options */
37
57
  options?: ComboBoxItem[];
58
+ /** Options organized into groups */
38
59
  groupedOptions?: ComboBoxGroup[];
39
- tooltipLocation?: "top" | "bottom" | "left" | "right";
60
+ /** Position of the tooltip */
61
+ tooltipLocation?: 'top' | 'bottom' | 'left' | 'right';
62
+ /** Async function to fetch options */
40
63
  fetchFunction?: FetchFunctionType | null;
64
+ /** Async function to search/filter options */
41
65
  searchFunction?: SearchFunctionType | null;
66
+ /** Async function to retrieve label for a value */
42
67
  retrieveLabelFunction?: RetrieveLabelFunctionType | null;
68
+ /** Rich tooltip content using a Svelte snippet */
43
69
  tooltipContent?: Snippet;
70
+ /** Simple tooltip text */
44
71
  tooltipText?: string;
72
+ /** Callback when selection changes (returns value string) */
45
73
  onchange?: (e: string | undefined) => void;
74
+ /** Callback when selection changes (returns full item object) */
46
75
  onchangeRaw?: (e: ComboBoxItem | undefined) => void;
76
+ /** HTML autocomplete attribute for the input */
77
+ autocomplete?: string;
47
78
  }
48
79
 
49
80
  let {
50
- label = "",
81
+ name,
82
+ label = '',
51
83
  value = $bindable(undefined),
52
84
  rawValue = undefined,
53
- placeholder = "\u00a0", // non-breaking space to prevent the height collapsing
54
- class: classes = "",
55
- containerClass = "",
85
+ placeholder = '\u00a0', // non-breaking space to prevent the height collapsing
86
+ class: classes = '',
87
+ containerClass = '',
56
88
  disabled = false,
57
89
  required = false,
58
90
  showError = false,
59
- errorText = "",
91
+ errorText = '',
60
92
  autofocus = false,
61
93
  autofocusDialog = false,
62
94
  allowSearch = false,
63
- showNoResultsMessage = true,
64
- loadingText = "",
95
+ hideNoResults = false,
96
+ loadingText = '',
65
97
  options = [],
66
98
  groupedOptions = [],
67
- tooltipLocation = "top",
99
+ tooltipLocation = 'top',
68
100
  fetchFunction = null,
69
101
  searchFunction = null,
70
102
  retrieveLabelFunction = null,
@@ -72,19 +104,37 @@
72
104
  tooltipText,
73
105
  onchange,
74
106
  onchangeRaw,
75
- }: Props = $props();
107
+ autocomplete
108
+ }: SelectProps = $props();
76
109
 
77
110
  // Use derived for computed allowSearch
78
111
  let computedAllowSearch = $derived(searchFunction ? true : allowSearch);
112
+ let resolvedName = $derived((name || label || autoName).replace(/[^a-zA-Z0-9_\-:.]/g, '_'));
79
113
 
80
114
  let internalValue = $state(value);
81
- let filterString = $state("");
82
- let preloading = $state(false);
83
- let searching = $state(false);
84
- let timeout: number;
85
-
86
- let allGroups: ComboBoxGroup[] = $state([]);
87
- let filteredGroups: ComboBoxGroup[] = $state([]);
115
+ let filterString = $state('');
116
+
117
+ const core = new ComboBoxCore({
118
+ getOptions: () => options,
119
+ getGroupedOptions: () => groupedOptions,
120
+ getValue: () => value,
121
+ setValue: (v) => (value = v),
122
+ setRawValue: (r) => (rawValue = r),
123
+ getFetchFunction: () => fetchFunction,
124
+ getSearchFunction: () => searchFunction,
125
+ getRetrieveLabelFunction: () => retrieveLabelFunction,
126
+ clearUnknownStatic: true,
127
+ onValueCleared: () => {
128
+ internalValue = undefined;
129
+ onchange?.(undefined);
130
+ onchangeRaw?.(undefined);
131
+ },
132
+ onRawValueResolved: (raw) => onchangeRaw?.(raw),
133
+ // Re-apply the active filter so a mid-search options swap doesn't drop results
134
+ onOptionsChanged: () => {
135
+ if (filterString) onFilterChange(filterString);
136
+ }
137
+ });
88
138
 
89
139
  let open = $state(false);
90
140
 
@@ -114,7 +164,7 @@
114
164
  focus();
115
165
  }, 150);
116
166
  }
117
- },
167
+ }
118
168
  });
119
169
 
120
170
  function focus() {
@@ -125,155 +175,48 @@
125
175
  $effect(() => {
126
176
  if (value !== internalValue) {
127
177
  internalValue = value;
128
- rawValue =
129
- allGroups
130
- .flatMap((x) => x.items)
131
- .find((x) => x.value === value) ?? undefined;
132
- isEmpty = rawValue === undefined;
133
- onchangeRaw?.(rawValue);
134
- preloadValues();
135
- }
136
- });
137
-
138
- function preloadValues() {
139
- if (!value) {
140
- rawValue = undefined;
141
- return;
142
- }
143
-
144
- const foundOption = allGroups
145
- .flatMap((x) => x.items)
146
- .find((x) => x.value === value);
147
-
148
- if (foundOption !== undefined) {
149
- rawValue = foundOption;
150
- } else if (searchFunction && retrieveLabelFunction) {
151
- preloading = true;
152
- retrieveLabelFunction(value).then((response) => {
153
- rawValue = {
154
- label: response.object ?? value!.toString(),
155
- value: value!,
156
- };
157
-
158
- preloading = false;
159
- });
160
- } else {
161
- rawValue = { label: value.toString(), value };
162
- }
163
- }
164
-
165
- function initOptions(opts: ComboBoxItem[]) {
166
- if (fetchFunction) {
167
- preloading = true;
168
- fetchFunction().then((response: NotifyModel<ComboBoxItem[]>) => {
169
- convertOptions(response.object!);
170
- preloadValues();
171
- preloading = false;
172
- });
173
- } else {
174
- if (groupedOptions.length) {
175
- convertGroupOptions(groupedOptions);
176
- } else if (opts.length) {
177
- convertOptions(opts);
178
- } else {
179
- filteredGroups = [];
178
+ const selfCleared = core.preloadValues();
179
+ // preloadValues fires its own callbacks on the clear path; don't double-notify
180
+ if (!selfCleared) {
181
+ onchangeRaw?.(rawValue);
180
182
  }
181
- preloadValues();
182
183
  }
183
- }
184
-
185
- onMount(() => {
186
- initOptions(options);
187
184
  });
188
185
 
189
- function convertOptions(options: ComboBoxItem[]) {
190
- const allOptions = options.map((option) => {
191
- return {
192
- ...option,
193
- selected: value === option.value,
194
- };
195
- });
196
- allGroups = [{ label: "", items: [...allOptions] }];
197
- filteredGroups = [{ label: "", items: [...allOptions] }];
198
- }
199
-
200
- function convertGroupOptions(groups: ComboBoxGroup[]) {
201
- allGroups = groups.map((group) => {
202
- return {
203
- ...group,
204
- items: group.items.map((option) => {
205
- return {
206
- ...option,
207
- selected: value === option.value,
208
- groupName: group.label,
209
- };
210
- }),
211
- };
212
- });
213
- filteredGroups = [...allGroups];
214
- }
215
-
216
186
  function onSelection(selectedValue: ComboBoxItem) {
217
- options.forEach((option) => {
218
- if (option.value === selectedValue.value)
219
- option.selected = selectedValue.selected;
187
+ core.allGroups.forEach((group) => {
188
+ group.items.forEach((item) => {
189
+ item.selected = item.value === selectedValue.value;
190
+ });
220
191
  });
221
192
 
222
193
  value = selectedValue.value;
194
+ internalValue = value;
223
195
  rawValue = selectedValue;
224
196
 
225
- onchange?.(value ? value : "");
197
+ onchange?.(value);
226
198
  onchangeRaw?.(rawValue);
227
199
 
228
200
  open = false;
229
201
  }
230
202
 
231
- function onFilterChange(value: string) {
232
- if (value.length === 0) {
233
- filteredGroups = allGroups;
234
- return;
235
- }
236
- if (searchFunction && value) {
237
- clearTimeout(timeout);
238
- searching = true;
239
- timeout = window.setTimeout(() => {
240
- searchFunction(value).then(
241
- (response: NotifyModel<ComboBoxItem[]>) => {
242
- convertOptions(response.object!);
243
- searching = false;
244
- open = true;
245
- },
246
- );
247
- }, 300);
248
- } else if (allGroups) {
249
- filteredGroups = allGroups.filter((group) =>
250
- group.items.some((x) =>
251
- x.label.toLowerCase().includes(value.toLowerCase()),
252
- ),
253
- );
254
-
255
- if (filteredGroups.length > 0) {
256
- filteredGroups = filteredGroups.map((group) => ({
257
- ...group,
258
- items: group.items.filter((x) =>
259
- x.label.toLowerCase().includes(value.toLowerCase()),
260
- ),
261
- }));
262
- }
203
+ function onFilterChange(filterValue: string) {
204
+ if (searchFunction && filterValue) {
205
+ core.search(filterValue, () => (open = true));
206
+ } else {
207
+ core.filterLocal(filterValue);
263
208
  }
264
209
  }
265
210
 
266
- let comboBoxEl: ReturnType<typeof ComboBoxMulti> | undefined =
267
- $state(undefined);
211
+ let comboBoxEl: ReturnType<typeof ComboBoxMulti> | undefined = $state(undefined);
268
212
  let textboxElement: HTMLElement | undefined = $state(undefined);
269
213
  let buttonElement: HTMLElement | undefined = $state(undefined);
270
- let comboBoxKeyDown: ((e: KeyboardEvent) => void) | undefined =
271
- $state(undefined);
214
+ let comboBoxKeyDown: ((e: KeyboardEvent) => void) | undefined = $state(undefined);
272
215
 
273
216
  function onKeyDown(e: KeyboardEvent) {
274
217
  if (!open) return;
275
218
 
276
- if (e.key === "Escape") {
219
+ if (e.key === 'Escape') {
277
220
  e.preventDefault();
278
221
  open = false;
279
222
  } else if (comboBoxKeyDown) {
@@ -284,10 +227,8 @@
284
227
  }
285
228
 
286
229
  function closePopover(e: MouseEvent) {
287
- if (textboxElement && textboxElement.contains(e.target as HTMLElement))
288
- return;
289
- if (buttonElement && buttonElement.contains(e.target as HTMLElement))
290
- return;
230
+ if (textboxElement && textboxElement.contains(e.target as HTMLElement)) return;
231
+ if (buttonElement && buttonElement.contains(e.target as HTMLElement)) return;
291
232
 
292
233
  open = false;
293
234
  }
@@ -295,31 +236,25 @@
295
236
  function copyCurrentValue() {
296
237
  if (rawValue?.label) {
297
238
  navigator.clipboard.writeText(rawValue.label).catch((err) => {
298
- console.error("Failed to copy text: ", err);
239
+ console.error('Failed to copy text: ', err);
299
240
  });
300
241
  }
301
242
  }
302
243
 
303
244
  const extraClasses: string[] = $derived.by(() => {
304
245
  const classes = [];
305
- if (open) classes.push("!border-accent");
306
- if (disabled) classes.push("disabled");
307
- if (showError) classes.push("show-error");
308
- if (computedAllowSearch) classes.push("searchable");
309
- if (open && !isEmpty) classes.push("has-actions");
246
+ if (open) classes.push('!border-accent');
247
+ if (disabled) classes.push('disabled');
248
+ if (showError) classes.push('show-error');
249
+ if (computedAllowSearch) classes.push('searchable');
250
+ if (open && !isEmpty) classes.push('has-actions');
310
251
 
311
252
  return classes;
312
253
  });
313
254
  </script>
314
255
 
315
256
  <div class="select-container {containerClass}">
316
- <FormGroup
317
- {label}
318
- {required}
319
- {tooltipContent}
320
- {tooltipText}
321
- {tooltipLocation}
322
- >
257
+ <FormGroup {label} {required} {tooltipContent} {tooltipText} {tooltipLocation}>
323
258
  {#if computedAllowSearch && open}
324
259
  <div class="select-input-wrapper">
325
260
  <input
@@ -327,12 +262,14 @@
327
262
  bind:value={filterString}
328
263
  oninput={() => onFilterChange(filterString)}
329
264
  onkeydown={onKeyDown}
330
- autocomplete="off"
331
- disabled={preloading || disabled}
332
- placeholder={isEmpty ? placeholder : rawValue?.label || ""}
265
+ name={resolvedName}
266
+ autocomplete={(autocomplete as any) ?? 'off'}
267
+ disabled={core.preloading || disabled}
268
+ placeholder={isEmpty ? placeholder : rawValue?.label || ''}
333
269
  class="select select-input {extraClasses} {classes}"
270
+ type="search"
334
271
  />
335
- {#if preloading || searching}
272
+ {#if core.preloading || core.searching}
336
273
  <div class="loader">
337
274
  <Loader sizeOverride="1.125rem" />
338
275
  </div>
@@ -352,18 +289,16 @@
352
289
  svg={iconX}
353
290
  size="0.75rem"
354
291
  onclick={(e: MouseEvent) => {
292
+ internalValue = undefined;
355
293
  value = undefined;
356
294
  rawValue = undefined;
357
- filterString = "";
358
- filteredGroups = allGroups;
295
+ filterString = '';
296
+ core.filteredGroups = core.allGroups;
359
297
 
360
298
  onchange?.(undefined);
361
299
  onchangeRaw?.(undefined);
362
300
 
363
- options.forEach((x) => (x.selected = false));
364
- allGroups
365
- .flatMap((x) => x.items)
366
- .forEach((x) => (x.selected = false));
301
+ core.allGroups.flatMap((x) => x.items).forEach((x) => (x.selected = false));
367
302
 
368
303
  e.stopPropagation();
369
304
  }}
@@ -385,25 +320,21 @@
385
320
  }
386
321
  }}
387
322
  onkeydown={(e) => onKeyDown(e)}
388
- disabled={preloading || disabled}
323
+ name={resolvedName}
324
+ disabled={core.preloading || disabled}
389
325
  class="select {extraClasses} {classes}"
390
326
  >
391
327
  {#if isEmpty}
392
- <span class="placeholder"
393
- >{preloading ? "Loading..." : placeholder}</span
394
- >
328
+ <span class="placeholder">{core.preloading ? 'Loading...' : placeholder}</span>
395
329
  {:else if rawValue?.selectedComponent}
396
330
  {@const DisplayComponent = rawValue.selectedComponent}
397
- <DisplayComponent
398
- option={rawValue}
399
- {...rawValue.selectedComponentProps}
400
- />
331
+ <DisplayComponent option={rawValue} {...rawValue.selectedComponentProps} />
401
332
  {:else}
402
333
  <span>
403
334
  {rawValue?.label}
404
335
  </span>
405
336
  {/if}
406
- {#if preloading || searching}
337
+ {#if core.preloading || core.searching}
407
338
  <div class="loader">
408
339
  <Loader sizeOverride="1.125rem" />
409
340
  </div>
@@ -423,16 +354,14 @@
423
354
  svg={iconX}
424
355
  size="0.75rem"
425
356
  onclick={(e: MouseEvent) => {
357
+ internalValue = undefined;
426
358
  value = undefined;
427
359
  rawValue = undefined;
428
360
 
429
361
  onchange?.(undefined);
430
362
  onchangeRaw?.(undefined);
431
363
 
432
- options.forEach((x) => (x.selected = false));
433
- allGroups
434
- .flatMap((x) => x.items)
435
- .forEach((x) => (x.selected = false));
364
+ core.allGroups.flatMap((x) => x.items).forEach((x) => (x.selected = false));
436
365
 
437
366
  e.stopPropagation();
438
367
  }}
@@ -458,10 +387,10 @@
458
387
  values={rawValue ? [rawValue] : []}
459
388
  {onSelection}
460
389
  onkeydown={comboBoxKeyDown}
461
- groupedOptions={filteredGroups}
390
+ groupedOptions={core.filteredGroups}
462
391
  {open}
463
- loading={searching}
464
- {showNoResultsMessage}
392
+ loading={core.searching}
393
+ {hideNoResults}
465
394
  {loadingText}
466
395
  />
467
396
  </div>
@@ -477,26 +406,26 @@
477
406
  }
478
407
 
479
408
  .select {
480
- font-size: var(--pui-font-size-md);
481
- line-height: var(--pui-line-height-normal);
409
+ font-size: 1rem;
410
+ line-height: 1.5rem;
482
411
  position: relative;
483
412
  display: flex;
484
413
  flex-wrap: wrap;
485
- padding: var(--pui-spacing-1) var(--pui-spacing-2);
486
- border-radius: var(--pui-radius-base);
414
+ padding: 0.25rem 0.5rem;
415
+ border-radius: 0.25rem;
487
416
  text-align: left;
488
- background-color: var(--pui-input-bg);
489
- color: var(--pui-text-primary);
490
- border-color: var(--pui-border-default);
417
+ background-color: var(--input-bg-color);
418
+ color: var(--text-color);
419
+ border-color: var(--border-color);
491
420
  cursor: pointer;
492
421
  width: 100%;
493
422
  align-items: center;
494
- border: 1px solid var(--pui-border-default);
495
- padding-right: var(--pui-spacing-8);
423
+ border: 1px solid var(--border-color);
424
+ padding-right: 2rem;
496
425
  }
497
426
 
498
427
  .select.has-actions {
499
- padding-right: var(--pui-spacing-14);
428
+ padding-right: 3.5rem;
500
429
  }
501
430
 
502
431
  .select.searchable {
@@ -504,9 +433,9 @@
504
433
  }
505
434
 
506
435
  .select:focus {
507
- border-color: var(--pui-input-border-focus);
436
+ border-color: var(--accent-color);
508
437
  outline: 2px solid transparent;
509
- outline-offset: var(--pui-focus-ring-offset);
438
+ outline-offset: 2px;
510
439
  }
511
440
 
512
441
  .select-input-wrapper {
@@ -520,10 +449,10 @@
520
449
 
521
450
  .select-icon {
522
451
  position: absolute;
523
- right: var(--pui-spacing-2);
452
+ right: 0.5rem;
524
453
  top: 50%;
525
454
  transform: translateY(-50%);
526
- width: var(--pui-spacing-4);
455
+ width: 1rem;
527
456
  display: flex;
528
457
  pointer-events: none;
529
458
  }
@@ -531,16 +460,16 @@
531
460
  .btn-clear-container {
532
461
  position: absolute;
533
462
  line-height: 0;
534
- right: var(--pui-spacing-2);
463
+ right: 0.5rem;
535
464
  top: 50%;
536
465
  transform: translateY(-50%);
537
466
  display: flex;
538
- gap: var(--pui-spacing-1);
467
+ gap: 0.25rem;
539
468
  }
540
469
 
541
470
  .select-btn-clear {
542
- border-radius: var(--pui-radius-base);
543
- padding: var(--pui-spacing-1);
471
+ border-radius: 0.25rem;
472
+ padding: 0.25rem;
544
473
  right: 0.4rem;
545
474
  }
546
475
 
@@ -548,9 +477,10 @@
548
477
  position: absolute;
549
478
  width: 100%;
550
479
  left: 0;
551
- z-index: var(--pui-z-dropdown);
480
+ z-index: 70;
552
481
  border-top-left-radius: 0;
553
482
  border-top-right-radius: 0;
483
+ /* absolute w-full left-0 z-20 */
554
484
  }
555
485
 
556
486
  .select-panel-inner {
@@ -559,7 +489,8 @@
559
489
  }
560
490
 
561
491
  .placeholder {
562
- color: var(--pui-text-placeholder);
492
+ color: var(--placeholder-color);
493
+ /* text-zinc-400 dark:text-neutral-500 */
563
494
  }
564
495
 
565
496
  .hidden {
@@ -569,22 +500,22 @@
569
500
  .disabled {
570
501
  opacity: 0.5;
571
502
  cursor: not-allowed;
572
- background-color: var(--pui-bg-disabled);
503
+ background-color: var(--border-color);
573
504
  }
574
505
 
575
506
  .loader {
576
507
  position: absolute;
577
- right: var(--pui-spacing-2_5);
508
+ right: 0.65rem;
578
509
  top: 50%;
579
510
  transform: translateY(-50%);
580
- width: var(--pui-spacing-4);
511
+ width: 1rem;
581
512
  }
582
513
 
583
514
  .show-error {
584
- border-color: var(--pui-text-danger);
515
+ border-color: var(--danger-text);
585
516
  }
586
517
 
587
518
  .text-error {
588
- color: var(--pui-text-danger);
519
+ color: var(--danger-text);
589
520
  }
590
521
  </style>