@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
@@ -0,0 +1,287 @@
1
+ <script lang="ts" module>
2
+ export interface MultiSortableProps<T> {
3
+ /** Items in this list — bindable so reorders and transfers write back */
4
+ items: T[];
5
+ /** Renders each item. Receives (item, index, dragging). */
6
+ children: import('svelte').Snippet<[T, number, boolean]>;
7
+ /** Stable key per item — defaults to index (not safe for reordered lists with snippets that need identity) */
8
+ getKey?: (item: T, index: number) => string | number;
9
+ /** Layout direction */
10
+ direction?: 'vertical' | 'horizontal';
11
+ /** When true, items can't be dragged out of this list (drops in are still allowed) */
12
+ disabled?: boolean;
13
+ /** CSS selector for drag handle within each item. When set, drag starts only from this element. */
14
+ handle?: string;
15
+ /** Group name — lists sharing a group can move items between each other */
16
+ group?: string;
17
+ /** FLIP animation duration in ms when items shift (reorder, receive, or transfer out).
18
+ * 0 disables. Requires a stable getKey — with the default index key nothing moves. */
19
+ animation?: number;
20
+ /** Gate incoming items from other lists. Return false to reject. Local reorders are always allowed. */
21
+ canReceive?: (item: T) => boolean;
22
+ /** Rendered when the list is empty — useful as a visible drop target for the first item. */
23
+ placeholder?: import('svelte').Snippet;
24
+ /** Fires when this list changes (reorder, item received, or item removed by transfer out) */
25
+ onChange?: (items: T[]) => void;
26
+ class?: string;
27
+ }
28
+ </script>
29
+
30
+ <script lang="ts" generics="T">
31
+ import { flip } from 'svelte/animate';
32
+ import { draggable, droppable, type DragContext } from '../util/DragDrop.js';
33
+
34
+ let {
35
+ items = $bindable(),
36
+ children,
37
+ getKey = (_: T, i: number) => i,
38
+ direction = 'vertical',
39
+ disabled = false,
40
+ handle,
41
+ group = 'default',
42
+ animation = 150,
43
+ canReceive,
44
+ placeholder,
45
+ onChange,
46
+ class: classes = ''
47
+ }: MultiSortableProps<T> = $props();
48
+
49
+ const SORTABLE_ID = Math.random().toString(36).slice(2);
50
+ const TYPE = $derived(`pui-multisortable:${group}`);
51
+
52
+ const reducedMotion =
53
+ typeof window !== 'undefined' && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
54
+ const flipDuration = $derived(reducedMotion ? 0 : animation);
55
+
56
+ interface MultiSortablePayload {
57
+ sortableId: string;
58
+ index: number;
59
+ item: T;
60
+ /** Removes the item from its source list — called by the target after inserting. */
61
+ onRemove: () => void;
62
+ }
63
+
64
+ let draggingIndex = $state<number | null>(null);
65
+ let dropIndex = $state<number | null>(null);
66
+ let dropPosition = $state<'before' | 'after'>('before');
67
+ let container = $state<HTMLElement>();
68
+
69
+ function removeAt(index: number) {
70
+ const next = items.slice();
71
+ next.splice(index, 1);
72
+ items = next;
73
+ // This runs when the item is transferred to another list, which detaches the dragged
74
+ // element from the DOM. A detached element never fires `dragend`, so onDragEnd won't
75
+ // reset our state — clear it here or the item shifting into this slot stays faded.
76
+ draggingIndex = null;
77
+ dropIndex = null;
78
+ onChange?.(next);
79
+ }
80
+
81
+ /** Reorder within this list (drag originated here). */
82
+ function applyMove(from: number, target: number, position: 'before' | 'after') {
83
+ let to = target + (position === 'after' ? 1 : 0);
84
+ if (to > from) to--;
85
+ if (from === to) return;
86
+ const next = items.slice();
87
+ const [moved] = next.splice(from, 1);
88
+ next.splice(to, 0, moved);
89
+ items = next;
90
+ onChange?.(next);
91
+ }
92
+
93
+ /** Insert an item received from another list at the current drop marker. */
94
+ function applyInsert(item: T, target: number | null, position: 'before' | 'after') {
95
+ const to = target === null ? items.length : target + (position === 'after' ? 1 : 0);
96
+ const next = items.slice();
97
+ next.splice(to, 0, item);
98
+ items = next;
99
+ onChange?.(next);
100
+ }
101
+
102
+ function accepts(ctx: DragContext<MultiSortablePayload>): boolean {
103
+ // Reorders from this same list are always allowed.
104
+ if (ctx.payload.sortableId === SORTABLE_ID) return true;
105
+ return !canReceive || canReceive(ctx.payload.item);
106
+ }
107
+
108
+ /**
109
+ * Positioning lives on the container (not per item) so empty lists, gaps, and
110
+ * the space after the last item are all valid drop targets. Walks the rendered
111
+ * item rects and picks the insertion marker from the pointer position.
112
+ */
113
+ function handleDragOver(e: DragEvent, ctx: DragContext<MultiSortablePayload>) {
114
+ if (!accepts(ctx)) return;
115
+ const host = container;
116
+ if (!host) return;
117
+ const itemEls = Array.from(
118
+ host.querySelectorAll<HTMLElement>(':scope > .pui-msortable-item')
119
+ );
120
+ if (itemEls.length === 0) {
121
+ dropIndex = null;
122
+ return;
123
+ }
124
+ for (let idx = 0; idx < itemEls.length; idx++) {
125
+ const rect = itemEls[idx].getBoundingClientRect();
126
+ const mid =
127
+ direction === 'vertical' ? rect.top + rect.height / 2 : rect.left + rect.width / 2;
128
+ const pointer = direction === 'vertical' ? e.clientY : e.clientX;
129
+ if (pointer < mid) {
130
+ dropIndex = idx;
131
+ dropPosition = 'before';
132
+ return;
133
+ }
134
+ }
135
+ dropIndex = itemEls.length - 1;
136
+ dropPosition = 'after';
137
+ }
138
+
139
+ function handleDrop(ctx: DragContext<MultiSortablePayload>) {
140
+ if (!accepts(ctx)) return;
141
+ if (ctx.payload.sortableId === SORTABLE_ID) {
142
+ // Local reorder — the dragged item is guaranteed to be in this list.
143
+ if (dropIndex !== null) applyMove(ctx.payload.index, dropIndex, dropPosition);
144
+ } else {
145
+ // Cross-list transfer: insert here, then have the source drop it.
146
+ applyInsert(ctx.payload.item, dropIndex, dropPosition);
147
+ ctx.payload.onRemove();
148
+ }
149
+ dropIndex = null;
150
+ }
151
+ </script>
152
+
153
+ <div
154
+ bind:this={container}
155
+ class="pui-msortable {direction} {classes}"
156
+ class:is-empty={items.length === 0}
157
+ use:droppable={{
158
+ accepts: TYPE,
159
+ canDrop: (ctx) => accepts(ctx as DragContext<MultiSortablePayload>),
160
+ onDragOver: (ctx, e) => handleDragOver(e, ctx as DragContext<MultiSortablePayload>),
161
+ onDragLeave: () => {
162
+ dropIndex = null;
163
+ },
164
+ onDrop: (ctx) => handleDrop(ctx as DragContext<MultiSortablePayload>)
165
+ }}
166
+ >
167
+ {#each items as item, i (getKey(item, i))}
168
+ <div
169
+ class="pui-msortable-item"
170
+ class:is-dragging={draggingIndex === i}
171
+ class:drop-before={dropIndex === i && dropPosition === 'before' && draggingIndex !== i}
172
+ class:drop-after={dropIndex === i && dropPosition === 'after' && draggingIndex !== i}
173
+ animate:flip={{ duration: flipDuration }}
174
+ use:draggable={{
175
+ payload: {
176
+ sortableId: SORTABLE_ID,
177
+ index: i,
178
+ item,
179
+ onRemove: () => removeAt(i)
180
+ } satisfies MultiSortablePayload,
181
+ type: TYPE,
182
+ source: SORTABLE_ID,
183
+ disabled,
184
+ handle,
185
+ onDragStart: () => {
186
+ draggingIndex = i;
187
+ },
188
+ onDragEnd: () => {
189
+ draggingIndex = null;
190
+ dropIndex = null;
191
+ }
192
+ }}
193
+ >
194
+ {@render children(item, i, draggingIndex === i)}
195
+ </div>
196
+ {/each}
197
+
198
+ {#if items.length === 0 && placeholder}
199
+ <div class="pui-msortable-placeholder">{@render placeholder()}</div>
200
+ {/if}
201
+ </div>
202
+
203
+ <style>
204
+ .pui-msortable {
205
+ display: flex;
206
+ gap: 0.25rem;
207
+ }
208
+
209
+ .pui-msortable.vertical {
210
+ flex-direction: column;
211
+ }
212
+
213
+ .pui-msortable.horizontal {
214
+ flex-direction: row;
215
+ }
216
+
217
+ /* Keep empty lists a valid, visible drop target. */
218
+ .pui-msortable.is-empty {
219
+ min-height: 2.5rem;
220
+ }
221
+
222
+ .pui-msortable-item {
223
+ position: relative;
224
+ transition: opacity 0.15s ease;
225
+ }
226
+
227
+ .pui-msortable-item.is-dragging {
228
+ opacity: 0.35;
229
+ }
230
+
231
+ .pui-msortable-item::before,
232
+ .pui-msortable-item::after {
233
+ content: '';
234
+ position: absolute;
235
+ background: var(--ui-tertiary);
236
+ border-radius: 2px;
237
+ opacity: 0;
238
+ pointer-events: none;
239
+ transition: opacity 0.1s ease;
240
+ }
241
+
242
+ .pui-msortable.vertical > .pui-msortable-item::before,
243
+ .pui-msortable.vertical > .pui-msortable-item::after {
244
+ left: 0;
245
+ right: 0;
246
+ height: 2px;
247
+ }
248
+
249
+ .pui-msortable.vertical > .pui-msortable-item::before {
250
+ top: -2px;
251
+ }
252
+
253
+ .pui-msortable.vertical > .pui-msortable-item::after {
254
+ bottom: -2px;
255
+ }
256
+
257
+ .pui-msortable.horizontal > .pui-msortable-item::before,
258
+ .pui-msortable.horizontal > .pui-msortable-item::after {
259
+ top: 0;
260
+ bottom: 0;
261
+ width: 2px;
262
+ }
263
+
264
+ .pui-msortable.horizontal > .pui-msortable-item::before {
265
+ left: -2px;
266
+ }
267
+
268
+ .pui-msortable.horizontal > .pui-msortable-item::after {
269
+ right: -2px;
270
+ }
271
+
272
+ .pui-msortable-item.drop-before::before {
273
+ opacity: 1;
274
+ }
275
+
276
+ .pui-msortable-item.drop-after::after {
277
+ opacity: 1;
278
+ }
279
+
280
+ .pui-msortable-placeholder {
281
+ flex: 1;
282
+ display: flex;
283
+ align-items: center;
284
+ justify-content: center;
285
+ pointer-events: none;
286
+ }
287
+ </style>
@@ -0,0 +1,50 @@
1
+ export interface MultiSortableProps<T> {
2
+ /** Items in this list — bindable so reorders and transfers write back */
3
+ items: T[];
4
+ /** Renders each item. Receives (item, index, dragging). */
5
+ children: import('svelte').Snippet<[T, number, boolean]>;
6
+ /** Stable key per item — defaults to index (not safe for reordered lists with snippets that need identity) */
7
+ getKey?: (item: T, index: number) => string | number;
8
+ /** Layout direction */
9
+ direction?: 'vertical' | 'horizontal';
10
+ /** When true, items can't be dragged out of this list (drops in are still allowed) */
11
+ disabled?: boolean;
12
+ /** CSS selector for drag handle within each item. When set, drag starts only from this element. */
13
+ handle?: string;
14
+ /** Group name — lists sharing a group can move items between each other */
15
+ group?: string;
16
+ /** FLIP animation duration in ms when items shift (reorder, receive, or transfer out).
17
+ * 0 disables. Requires a stable getKey — with the default index key nothing moves. */
18
+ animation?: number;
19
+ /** Gate incoming items from other lists. Return false to reject. Local reorders are always allowed. */
20
+ canReceive?: (item: T) => boolean;
21
+ /** Rendered when the list is empty — useful as a visible drop target for the first item. */
22
+ placeholder?: import('svelte').Snippet;
23
+ /** Fires when this list changes (reorder, item received, or item removed by transfer out) */
24
+ onChange?: (items: T[]) => void;
25
+ class?: string;
26
+ }
27
+ declare function $$render<T>(): {
28
+ props: MultiSortableProps<T>;
29
+ exports: {};
30
+ bindings: "items";
31
+ slots: {};
32
+ events: {};
33
+ };
34
+ declare class __sveltets_Render<T> {
35
+ props(): ReturnType<typeof $$render<T>>['props'];
36
+ events(): ReturnType<typeof $$render<T>>['events'];
37
+ slots(): ReturnType<typeof $$render<T>>['slots'];
38
+ bindings(): "items";
39
+ exports(): {};
40
+ }
41
+ interface $$IsomorphicComponent {
42
+ new <T>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
43
+ $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
44
+ } & ReturnType<__sveltets_Render<T>['exports']>;
45
+ <T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
46
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
47
+ }
48
+ declare const MultiSortable: $$IsomorphicComponent;
49
+ type MultiSortable<T> = InstanceType<typeof MultiSortable<T>>;
50
+ export default MultiSortable;
@@ -4,10 +4,14 @@
4
4
  import ActionIcon from './ActionIcon.svelte';
5
5
  import { iconChevronLeft } from '../icon/index.js';
6
6
 
7
- interface Props {
7
+ export interface PaginationProps {
8
+ /** Currently selected page number (bindable) */
8
9
  selectedPage?: number;
10
+ /** Total number of pages */
9
11
  totalPages?: number;
12
+ /** Callback when page changes */
10
13
  onPageChange?: (page: number) => void;
14
+ /** Maximum number of page buttons to display */
11
15
  maxPageButtons?: number;
12
16
  }
13
17
 
@@ -16,7 +20,7 @@
16
20
  totalPages,
17
21
  onPageChange = (page: number) => {},
18
22
  maxPageButtons = 8
19
- }: Props = $props();
23
+ }: PaginationProps = $props();
20
24
 
21
25
  type Page = { page: number | undefined; isSelected: boolean };
22
26
 
@@ -25,7 +29,9 @@
25
29
 
26
30
  selectedPage = page;
27
31
  onPageChange(page);
28
- } function determinePages(selectedPage: number, totalPages?: number) {
32
+ }
33
+
34
+ function determinePages(selectedPage: number, totalPages: number | undefined = undefined) {
29
35
  let pages: Page[] = [];
30
36
 
31
37
  function push(page: number | undefined) {
@@ -90,7 +96,7 @@
90
96
  <div class="pagination-container">
91
97
  <ActionIcon
92
98
  svg={iconChevronLeft}
93
- variant="primary-outline"
99
+ variant="secondary"
94
100
  onclick={() => setPage(selectedPage - 1)}
95
101
  disabled={selectedPage <= 1}
96
102
  />
@@ -98,7 +104,7 @@
98
104
  {#each determinePages(selectedPage, totalPages) as page}
99
105
  {#if page.page}
100
106
  <Button
101
- variant={page.isSelected ? 'primary' : 'primary-outline'}
107
+ variant={page.isSelected ? 'secondary-selected' : 'secondary'}
102
108
  class="paginate-button"
103
109
  onclick={() => setPage(page.page!)}>{page.page}</Button
104
110
  >
@@ -109,7 +115,7 @@
109
115
 
110
116
  <ActionIcon
111
117
  svg={chevronRight}
112
- variant="primary-outline"
118
+ variant="secondary"
113
119
  disabled={totalPages === undefined || selectedPage >= totalPages}
114
120
  onclick={() => setPage(selectedPage + 1)}
115
121
  />
@@ -119,7 +125,7 @@
119
125
  .pagination-container {
120
126
  display: flex;
121
127
  align-items: center;
122
- gap: var(--pui-spacing-2);
128
+ gap: 0.5rem;
123
129
  }
124
130
 
125
131
  .pagination-container :global(.paginate-button) {
@@ -128,8 +134,8 @@
128
134
  display: flex;
129
135
  justify-content: center;
130
136
  }
131
-
137
+
132
138
  :global(.dark) .pagination-container :global(.paginate-button.secondary-selected) {
133
- color: var(--pui-color-black);
139
+ color: black;
134
140
  }
135
141
  </style>
@@ -1,9 +1,13 @@
1
- interface Props {
1
+ export interface PaginationProps {
2
+ /** Currently selected page number (bindable) */
2
3
  selectedPage?: number;
4
+ /** Total number of pages */
3
5
  totalPages?: number;
6
+ /** Callback when page changes */
4
7
  onPageChange?: (page: number) => void;
8
+ /** Maximum number of page buttons to display */
5
9
  maxPageButtons?: number;
6
10
  }
7
- declare const Pagination: import("svelte").Component<Props, {}, "selectedPage">;
11
+ declare const Pagination: import("svelte").Component<PaginationProps, {}, "selectedPage">;
8
12
  type Pagination = ReturnType<typeof Pagination>;
9
13
  export default Pagination;
@@ -1,41 +1,50 @@
1
1
  <!-- drop down component that displays a button, when clicked on the children expand -->
2
2
  <script lang="ts">
3
- import type { Snippet } from "svelte";
4
- import Button from "./Button.svelte";
5
- import { clickOutside } from "../actions/ClickOutside.js";
3
+ import type { Snippet } from 'svelte';
4
+ import Button from './Button.svelte';
5
+ import { clickOutside } from '../util/ClickOutside.js';
6
6
 
7
- type PopoverPosition = "top" | "bottom" | "bottom-left" | "bottom-right" | "left" | "right";
8
- type PopoverTrigger = "click" | "hover";
7
+ type PopoverPosition = 'top' | 'bottom' | 'left' | 'right';
8
+ type PopoverTrigger = 'click' | 'hover';
9
9
 
10
- interface Props {
10
+ export interface PopoverProps {
11
+ /** Whether the popover is visible (bindable) */
11
12
  show?: boolean;
13
+ /** Text label for the default trigger button */
12
14
  label?: string | undefined;
15
+ /** Position of the popover relative to trigger */
13
16
  position?: PopoverPosition;
17
+ /** Additional CSS classes */
14
18
  class?: string;
19
+ /** Custom width for the popover content */
15
20
  cssWidth?: string;
21
+ /** Custom trigger button content */
16
22
  button?: Snippet;
23
+ /** Popover content */
17
24
  children?: Snippet;
25
+ /** How to trigger the popover */
18
26
  trigger?: PopoverTrigger;
27
+ /** Delay before showing on hover (ms) */
19
28
  hoverDelay?: number;
20
29
  }
21
30
 
22
31
  let {
23
32
  show = $bindable(false),
24
33
  label,
25
- position = "bottom",
26
- class: classes = "",
27
- cssWidth = "auto",
34
+ position = 'bottom',
35
+ class: classes = '',
36
+ cssWidth = 'auto',
28
37
  button,
29
38
  children,
30
- trigger = "click",
31
- hoverDelay = 1000,
32
- }: Props = $props();
39
+ trigger = 'click',
40
+ hoverDelay = 1000
41
+ }: PopoverProps = $props();
33
42
 
34
43
  let hoverTimeout: ReturnType<typeof setTimeout> | null = null;
35
44
  let isHovering = false;
36
45
 
37
46
  function handleMouseEnter() {
38
- if (trigger === "hover") {
47
+ if (trigger === 'hover') {
39
48
  isHovering = true;
40
49
  hoverTimeout = setTimeout(() => {
41
50
  if (isHovering) {
@@ -46,7 +55,7 @@
46
55
  }
47
56
 
48
57
  function handleMouseLeave() {
49
- if (trigger === "hover") {
58
+ if (trigger === 'hover') {
50
59
  isHovering = false;
51
60
  if (hoverTimeout) {
52
61
  clearTimeout(hoverTimeout);
@@ -62,19 +71,19 @@
62
71
  }
63
72
 
64
73
  function handleClick() {
65
- if (trigger === "click") {
74
+ if (trigger === 'click') {
66
75
  show = !show;
67
76
  }
68
77
  }
69
78
 
70
79
  function handleContentMouseEnter() {
71
- if (trigger === "hover") {
80
+ if (trigger === 'hover') {
72
81
  isHovering = true;
73
82
  }
74
83
  }
75
84
 
76
85
  function handleContentMouseLeave() {
77
- if (trigger === "hover") {
86
+ if (trigger === 'hover') {
78
87
  isHovering = false;
79
88
  setTimeout(() => {
80
89
  if (!isHovering) {
@@ -85,15 +94,12 @@
85
94
  }
86
95
  </script>
87
96
 
88
- <div class="popover-wrapper">
89
- <div
90
- class="popover {classes}"
91
- use:clickOutside={() => trigger === "click" && (show = false)}
92
- >
97
+ <div class="d-flex">
98
+ <div class="popover {classes}" use:clickOutside={() => trigger === 'click' && (show = false)}>
93
99
  {#if button}
94
100
  <!-- svelte-ignore a11y_no_static_element_interactions -->
95
101
  <!-- svelte-ignore a11y_mouse_events_have_key_events -->
96
- <button
102
+ <button
97
103
  onclick={handleClick}
98
104
  onmouseenter={handleMouseEnter}
99
105
  onmouseleave={handleMouseLeave}
@@ -130,10 +136,6 @@
130
136
  </div>
131
137
 
132
138
  <style>
133
- .popover-wrapper {
134
- display: flex;
135
- }
136
-
137
139
  .popover {
138
140
  position: relative;
139
141
  }
@@ -141,12 +143,12 @@
141
143
  .popover-content {
142
144
  display: block;
143
145
  position: absolute;
144
- background-color: var(--pui-paper-body-bg);
145
- border: 1px solid var(--pui-border-default);
146
+ background-color: var(--paper-body-bg);
147
+ border: 1px solid var(--border-color);
146
148
  min-width: 160px;
147
- box-shadow: var(--pui-shadow-lg);
148
- z-index: var(--pui-z-dropdown);
149
- border-radius: var(--pui-radius-base);
149
+ box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
150
+ z-index: 1000;
151
+ border-radius: 4px;
150
152
  }
151
153
 
152
154
  /* Position-specific styles */
@@ -154,45 +156,33 @@
154
156
  top: 100%;
155
157
  left: 50%;
156
158
  transform: translateX(-50%);
157
- margin-top: var(--pui-spacing-1);
158
- }
159
-
160
- .popover-bottom-left {
161
- top: 100%;
162
- right: calc(50% - 16px);
163
- margin-top: var(--pui-spacing-1);
164
- }
165
-
166
- .popover-bottom-right {
167
- top: 100%;
168
- left: calc(50% - 16px);
169
- margin-top: var(--pui-spacing-1);
159
+ margin-top: 4px;
170
160
  }
171
161
 
172
162
  .popover-top {
173
163
  bottom: 100%;
174
164
  left: 50%;
175
165
  transform: translateX(-50%);
176
- margin-bottom: var(--pui-spacing-1);
166
+ margin-bottom: 4px;
177
167
  }
178
168
 
179
169
  .popover-right {
180
170
  top: 50%;
181
171
  left: 100%;
182
172
  transform: translateY(-50%);
183
- margin-left: var(--pui-spacing-1);
173
+ margin-left: 4px;
184
174
  }
185
175
 
186
176
  .popover-left {
187
177
  top: 50%;
188
178
  right: 100%;
189
179
  transform: translateY(-50%);
190
- margin-right: var(--pui-spacing-1);
180
+ margin-right: 4px;
191
181
  }
192
182
 
193
183
  /* Arrow indicators for each position */
194
184
  .popover-content::before {
195
- content: "";
185
+ content: '';
196
186
  position: absolute;
197
187
  border: 6px solid transparent;
198
188
  }
@@ -201,40 +191,28 @@
201
191
  top: -12px;
202
192
  left: 50%;
203
193
  transform: translateX(-50%);
204
- border-bottom-color: var(--pui-border-default);
205
- }
206
-
207
- .popover-bottom-left::before {
208
- top: -12px;
209
- right: 12px;
210
- border-bottom-color: var(--pui-border-default);
211
- }
212
-
213
- .popover-bottom-right::before {
214
- top: -12px;
215
- left: 12px;
216
- border-bottom-color: var(--pui-border-default);
194
+ border-bottom-color: var(--border-color);
217
195
  }
218
196
 
219
197
  .popover-top::before {
220
198
  bottom: -12px;
221
199
  left: 50%;
222
200
  transform: translateX(-50%);
223
- border-top-color: var(--pui-border-default);
201
+ border-top-color: var(--border-color);
224
202
  }
225
203
 
226
204
  .popover-right::before {
227
205
  top: 50%;
228
206
  left: -12px;
229
207
  transform: translateY(-50%);
230
- border-right-color: var(--pui-border-default);
208
+ border-right-color: var(--border-color);
231
209
  }
232
210
 
233
211
  .popover-left::before {
234
212
  top: 50%;
235
213
  right: -12px;
236
214
  transform: translateY(-50%);
237
- border-left-color: var(--pui-border-default);
215
+ border-left-color: var(--border-color);
238
216
  }
239
217
 
240
218
  /* clear all button styles */