@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
@@ -3,17 +3,37 @@
3
3
  import { iconX } from '../icon/index.js';
4
4
  import type { Snippet } from 'svelte';
5
5
  import ActionIcon from './ActionIcon.svelte';
6
- import { setContext } from 'svelte';
6
+ import { setContext, untrack } from 'svelte';
7
+
8
+ export interface DialogContext {
9
+ /** Whether the dialog is currently open (reactive) */
10
+ readonly isOpen: boolean;
11
+ /** Register a callback invoked each time the dialog opens */
12
+ onOpen: (callback: () => void) => void;
13
+ /** Register a callback invoked each time the dialog closes */
14
+ onClose: (callback: () => void) => void;
15
+ /** Register a callback invoked only the first time the dialog opens */
16
+ onFirstOpen: (callback: () => void) => void;
17
+ }
7
18
 
8
- interface Props {
19
+ export interface DialogProps {
20
+ /** Whether the dialog is visible (bindable) */
9
21
  show: boolean;
22
+ /** Allow closing by clicking backdrop or pressing Escape */
10
23
  allowImplicitClose?: boolean;
24
+ /** Dialog title displayed in the header */
11
25
  title?: string | undefined;
26
+ /** Render without the Paper wrapper component */
12
27
  noPaper?: boolean;
28
+ /** Prevent content from overflowing the dialog bounds */
13
29
  preventOverflow?: boolean;
30
+ /** Size preset for the dialog width */
14
31
  size?: 'sm' | 'md' | 'lg' | 'xl' | 'full';
32
+ /** Additional CSS classes */
15
33
  class?: string;
34
+ /** Footer content (typically action buttons) */
16
35
  footer?: Snippet;
36
+ /** Main dialog content */
17
37
  children?: Snippet;
18
38
  }
19
39
 
@@ -27,83 +47,102 @@
27
47
  class: classes = '',
28
48
  footer,
29
49
  children
30
- }: Props = $props();
50
+ }: DialogProps = $props();
51
+
52
+ const uid = $props.id();
53
+ const titleId = `${uid}-title`;
31
54
 
32
55
  let dialogElement: HTMLDialogElement | undefined = $state(undefined);
33
-
34
- // Create context for dialog events
35
- let hasOpenedBefore = $state(false);
36
- let dialogContext = $state({
37
- isOpen: show,
38
- onOpen: () => {},
39
- onClose: () => {},
40
- onFirstOpen: () => {}
41
- });
42
56
 
43
- $effect(() => {
44
- dialogContext.isOpen = show;
57
+ // Context so child components can react to dialog state
58
+ const openCallbacks: (() => void)[] = [];
59
+ const closeCallbacks: (() => void)[] = [];
60
+ const firstOpenCallbacks: (() => void)[] = [];
61
+
62
+ setContext<DialogContext>('dialog', {
63
+ get isOpen() {
64
+ return show;
65
+ },
66
+ onOpen: (callback) => openCallbacks.push(callback),
67
+ onClose: (callback) => closeCallbacks.push(callback),
68
+ onFirstOpen: (callback) => firstOpenCallbacks.push(callback)
45
69
  });
46
70
 
47
- // Set context so child components can access dialog state
48
- setContext('dialog', dialogContext);
71
+ // Plain (untracked) flags — only the `show` transition should re-run the effect
72
+ let wasOpen = false;
73
+ let hasOpenedBefore = false;
49
74
 
50
75
  $effect(() => {
51
- if (dialogElement) {
52
- if (show) {
53
- dialogElement.showModal();
54
- dialogContext.onOpen();
76
+ if (!dialogElement) return;
77
+
78
+ if (show && !wasOpen) {
79
+ wasOpen = true;
80
+ dialogElement.showModal();
81
+ untrack(() => {
82
+ for (const callback of openCallbacks) callback();
55
83
  if (!hasOpenedBefore) {
56
84
  hasOpenedBefore = true;
57
- dialogContext.onFirstOpen();
85
+ for (const callback of firstOpenCallbacks) callback();
58
86
  }
59
- } else {
60
- dialogElement.close();
61
- dialogContext.onClose();
62
- }
87
+ });
88
+ } else if (!show && wasOpen) {
89
+ wasOpen = false;
90
+ dialogElement.close();
91
+ untrack(() => {
92
+ for (const callback of closeCallbacks) callback();
93
+ });
63
94
  }
64
95
  });
65
96
 
97
+ // Lock body scroll while open; effects only run in the browser, so this is SSR-safe
66
98
  $effect(() => {
67
- if (!body) return;
68
-
69
99
  if (show) {
70
- body.style.overflow = 'hidden';
71
- } else {
72
- body.style.overflow = '';
100
+ document.body.style.overflow = 'hidden';
101
+ return () => {
102
+ document.body.style.overflow = '';
103
+ };
73
104
  }
74
105
  });
75
106
 
76
- const body = document.querySelector('body');
107
+ function onCancel(e: Event) {
108
+ // Escape closes the native dialog before `close` fires; block it here,
109
+ // otherwise the dialog closes while `show` stays true
110
+ if (!allowImplicitClose) e.preventDefault();
111
+ }
112
+
113
+ function onNativeClose() {
114
+ // The dialog has already closed natively (Escape, form method="dialog");
115
+ // sync `show` unconditionally so it can be reopened
116
+ show = false;
117
+ }
77
118
 
78
- function onClose() {
119
+ function onBackdropMousedown() {
79
120
  if (allowImplicitClose) show = false;
80
121
  }
81
122
 
82
- function cancel(e: Event) {
83
- e.stopImmediatePropagation();
123
+ function stopMousedown(e: Event) {
124
+ // Keep mousedowns inside the dialog from reaching the backdrop handler
125
+ e.stopPropagation();
84
126
  }
85
127
  </script>
86
128
 
87
129
  {#snippet DialogInner()}
88
130
  {#if title}
89
131
  <div class="dialog-title">
90
- <span class="font-bold">{title}</span>
132
+ <span id={titleId} class="font-bold">{title}</span>
91
133
  {#if allowImplicitClose}
92
134
  <ActionIcon
93
- onclick={onClose}
135
+ onclick={() => (show = false)}
94
136
  variant="secondary-subtle"
95
137
  class="flex !p-[0.3rem] mr-1 !leading-0"
96
138
  svg={iconX}
97
139
  size="1rem"
140
+ ariaLabel="Close dialog"
98
141
  />
99
142
  {/if}
100
143
  </div>
101
144
  {/if}
102
- <div
103
- class="dialog-body
104
- {preventOverflow ? 'overflow-y-auto' : 'overflow-visible'}
105
- {!footer && 'no-footer'}"
106
- >
145
+ <div class="dialog-body {preventOverflow ? 'overflow-y-auto' : 'overflow-visible'}">
107
146
  {@render children?.()}
108
147
  </div>
109
148
  {#if footer}
@@ -113,64 +152,71 @@
113
152
  {/if}
114
153
  {/snippet}
115
154
 
116
- {#if noPaper}
117
- <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
118
- <dialog
119
- bind:this={dialogElement}
120
- onclose={onClose}
121
- onmousedown={onClose}
122
- class={`dialog ${size}`}
155
+ <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
156
+ <dialog
157
+ bind:this={dialogElement}
158
+ oncancel={onCancel}
159
+ onclose={onNativeClose}
160
+ onmousedown={onBackdropMousedown}
161
+ class={`dialog ${size}`}
162
+ aria-labelledby={title ? titleId : undefined}
163
+ >
164
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
165
+ <div
166
+ class="dialog-inner {noPaper ? `${classes} dialog-no-paper` : ''}"
167
+ onmousedown={stopMousedown}
123
168
  >
124
- <!-- svelte-ignore a11y_click_events_have_key_events -->
125
- <!-- svelte-ignore a11y_no_static_element_interactions -->
126
- <div
127
- class="dialog-inner {classes} dialog-no-paper"
128
- onclick={cancel}
129
- onmousedown={cancel}
130
- onmouseup={cancel}
131
- >
169
+ {#if noPaper}
132
170
  {@render DialogInner()}
133
- </div>
134
- </dialog>
135
- {:else}
136
- <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
137
- <dialog
138
- bind:this={dialogElement}
139
- onclose={onClose}
140
- onmousedown={onClose}
141
- class={`dialog ${size}`}
142
- >
143
- <!-- svelte-ignore a11y_click_events_have_key_events -->
144
- <!-- svelte-ignore a11y_no_static_element_interactions -->
145
- <div class="dialog-inner" onclick={cancel} onmousedown={cancel} onmouseup={cancel}>
146
- <div class="dialog-paper {preventOverflow ? 'overflow-y-auto' : 'overflow-visible'} ">
171
+ {:else}
172
+ <div class="dialog-paper {preventOverflow ? 'overflow-y-auto' : 'overflow-visible'}">
147
173
  <Paper containerClass={classes}>
148
174
  {@render DialogInner()}
149
175
  </Paper>
150
176
  </div>
151
- </div>
152
- </dialog>
153
- {/if}
177
+ {/if}
178
+ </div>
179
+ </dialog>
154
180
 
155
181
  <style>
182
+ /* Animate transform, not margin — the native dialog centers itself via
183
+ `margin: auto`, and a margin animation with `forwards` fill would
184
+ permanently override it and pin the dialog to the top of the viewport */
156
185
  @keyframes fadeIn {
157
186
  from {
158
187
  opacity: 0;
159
- transform: translateY(-1em);
188
+ transform: translateY(-0.5rem);
160
189
  }
161
190
  to {
162
191
  opacity: 1;
163
- transform: translateY(0em);
192
+ transform: translateY(0);
164
193
  }
165
194
  }
166
195
  @keyframes fadeOut {
167
196
  from {
168
197
  opacity: 1;
169
- transform: translateY(0em);
198
+ transform: translateY(0);
199
+ }
200
+ to {
201
+ opacity: 0;
202
+ transform: translateY(-0.5rem);
203
+ }
204
+ }
205
+
206
+ @keyframes fadeInFull {
207
+ from {
208
+ opacity: 0;
209
+ }
210
+ to {
211
+ opacity: 1;
212
+ }
213
+ }
214
+ @keyframes fadeOutFull {
215
+ from {
216
+ opacity: 1;
170
217
  }
171
218
  to {
172
219
  opacity: 0;
173
- transform: translateY(-1em);
174
220
  }
175
221
  }
176
222
 
@@ -193,54 +239,79 @@
193
239
  }
194
240
 
195
241
  dialog {
196
- color: var(--pui-text-primary);
242
+ color: var(--text-color);
197
243
  border: none;
244
+ /* The dialog element itself is focused by showModal(); don't draw a
245
+ focus ring around the whole dialog */
246
+ outline: none;
198
247
  background-color: transparent;
199
248
  overflow: visible;
200
249
  margin: auto;
201
-
202
- animation: fadeOut var(--pui-transition-fast) forwards;
250
+ max-width: min(calc(100vw - 2rem), calc(100% - 6px));
251
+ /* Cap to the visible viewport with equal margins; the flex chain below
252
+ (dialog > inner > paper > body, each min-height: 0) passes this limit
253
+ down so the body shrinks instead of spilling past the bottom edge.
254
+ dvh tracks the visible viewport on iOS Safari (100vh includes the
255
+ area behind the collapsible URL bar); vh is the older-browser fallback */
256
+ max-height: calc(100vh - 2rem);
257
+ max-height: calc(100dvh - 2rem);
258
+
259
+ animation: fadeOut 0.2s forwards;
203
260
  transition:
204
- display var(--pui-transition-fast) allow-discrete,
205
- overlay var(--pui-transition-fast) allow-discrete;
261
+ display 0.2s allow-discrete,
262
+ overlay 0.2s allow-discrete;
206
263
  &::backdrop {
207
- animation: backdropFadeOut var(--pui-transition-fast) forwards;
264
+ animation: backdropFadeOut 0.2s forwards;
208
265
  }
209
266
  &[open] {
210
- animation: fadeIn var(--pui-transition-fast) forwards;
267
+ /* Only when [open] — an unconditional author display would override
268
+ the UA's display: none on closed dialogs and make them visible */
269
+ display: flex;
270
+ flex-direction: column;
271
+ animation: fadeIn 0.2s forwards;
211
272
  &::backdrop {
212
- animation: backdropFadeIn var(--pui-transition-fast) forwards;
273
+ animation: backdropFadeIn 0.2s forwards;
213
274
  }
214
275
  }
215
276
  }
216
277
 
278
+ .dialog-inner {
279
+ display: flex;
280
+ flex-direction: column;
281
+ min-height: 0;
282
+ }
283
+
284
+ /* Paper sits inside the height chain; .paper-body already has an inline
285
+ min-height: 0, so only .paper needs the shrink link */
286
+ .dialog :global(.paper) {
287
+ min-height: 0;
288
+ }
289
+
217
290
  .dialog-title {
218
291
  display: flex;
219
292
  justify-content: space-between;
220
- margin-bottom: var(--pui-spacing-2);
221
- padding-bottom: var(--pui-spacing-1);
222
- border-bottom: 1px solid var(--pui-border-default);
223
- font-weight: var(--pui-font-weight-semibold);
293
+ margin-bottom: 0.5rem;
294
+ padding-bottom: 0.25rem;
295
+ border-bottom: 1px solid var(--border-color);
296
+ font-weight: 600;
297
+ flex-shrink: 0;
224
298
  }
225
299
 
226
300
  .dialog-body {
227
301
  display: flex;
228
302
  flex-direction: column;
229
303
  min-width: 0;
304
+ min-height: 0;
230
305
  flex-shrink: 1;
231
- max-height: calc(100vh - 167px);
232
- }
233
-
234
- .dialog-body.no-footer {
235
- max-height: calc(100vh - 107px);
236
306
  }
237
307
 
238
308
  .dialog-footer {
239
309
  display: flex;
240
- justify-content: flex-end;
241
- padding: var(--pui-spacing-2) 0;
242
- border-top: 1px solid var(--pui-border-default);
243
- gap: var(--pui-spacing-2);
310
+ justify-content: space-between;
311
+ padding-top: 0.5rem;
312
+ border-top: 1px solid var(--border-color);
313
+ gap: 0.5rem;
314
+ flex-shrink: 0;
244
315
  }
245
316
 
246
317
  .overflow-visible {
@@ -252,7 +323,7 @@
252
323
  }
253
324
 
254
325
  .dialog-no-paper {
255
- padding: var(--pui-spacing-4);
326
+ padding: 1rem;
256
327
  }
257
328
 
258
329
  .dialog-paper,
@@ -260,17 +331,18 @@
260
331
  display: flex;
261
332
  flex-direction: column;
262
333
  box-sizing: border-box;
263
- border-radius: var(--pui-radius-base);
264
- background: var(--pui-color-gray-100);
334
+ border-radius: 0.25rem;
335
+ background: #f1f3f5;
336
+ min-height: 0;
265
337
  }
266
338
 
267
339
  :global(.dark .dialog-paper),
268
340
  :global(.dark .dialog-no-paper) {
269
- background-color: var(--pui-color-dark-200);
341
+ background-color: rgb(33, 34, 38);
270
342
  }
271
343
 
272
344
  dialog::backdrop {
273
- background-color: var(--pui-bg-overlay);
345
+ background-color: #0008;
274
346
  }
275
347
 
276
348
  .dialog.sm {
@@ -291,13 +363,20 @@
291
363
 
292
364
  .dialog.full {
293
365
  width: 100%;
366
+ max-width: 100%;
367
+ max-height: 100%;
294
368
  margin-top: auto;
369
+ animation: fadeOutFull 0.2s forwards;
370
+
371
+ &[open] {
372
+ animation: fadeInFull 0.2s forwards;
373
+ }
295
374
  }
296
375
 
297
376
  .dialog.full,
298
377
  .dialog.full .dialog-inner,
299
378
  .dialog.full :global(.paper),
300
- .dialog.full :global(.dialog-paper) {
379
+ .dialog.full .dialog-paper {
301
380
  height: 100%;
302
381
  }
303
382
 
@@ -1,15 +1,34 @@
1
1
  import type { Snippet } from 'svelte';
2
- interface Props {
2
+ export interface DialogContext {
3
+ /** Whether the dialog is currently open (reactive) */
4
+ readonly isOpen: boolean;
5
+ /** Register a callback invoked each time the dialog opens */
6
+ onOpen: (callback: () => void) => void;
7
+ /** Register a callback invoked each time the dialog closes */
8
+ onClose: (callback: () => void) => void;
9
+ /** Register a callback invoked only the first time the dialog opens */
10
+ onFirstOpen: (callback: () => void) => void;
11
+ }
12
+ export interface DialogProps {
13
+ /** Whether the dialog is visible (bindable) */
3
14
  show: boolean;
15
+ /** Allow closing by clicking backdrop or pressing Escape */
4
16
  allowImplicitClose?: boolean;
17
+ /** Dialog title displayed in the header */
5
18
  title?: string | undefined;
19
+ /** Render without the Paper wrapper component */
6
20
  noPaper?: boolean;
21
+ /** Prevent content from overflowing the dialog bounds */
7
22
  preventOverflow?: boolean;
23
+ /** Size preset for the dialog width */
8
24
  size?: 'sm' | 'md' | 'lg' | 'xl' | 'full';
25
+ /** Additional CSS classes */
9
26
  class?: string;
27
+ /** Footer content (typically action buttons) */
10
28
  footer?: Snippet;
29
+ /** Main dialog content */
11
30
  children?: Snippet;
12
31
  }
13
- declare const Dialog: import("svelte").Component<Props, {}, "show">;
32
+ declare const Dialog: import("svelte").Component<DialogProps, {}, "show">;
14
33
  type Dialog = ReturnType<typeof Dialog>;
15
34
  export default Dialog;