@widgetic/design-system 0.5.22 → 0.5.24

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 (258) hide show
  1. package/README.md +2 -0
  2. package/dist/components/CopyableHeader.svelte +260 -448
  3. package/dist/components/CopyableHeader.svelte.d.ts +8 -5
  4. package/dist/components/EmptyState.svelte +100 -128
  5. package/dist/components/EmptyState.svelte.d.ts +16 -19
  6. package/dist/components/GenerateLoader.svelte +17 -10
  7. package/dist/components/PasswordInput.svelte +41 -44
  8. package/dist/components/PasswordInput.svelte.d.ts +2 -0
  9. package/dist/components/ThumbHashImage.svelte +117 -119
  10. package/dist/components/WScrollArea.svelte +47 -41
  11. package/dist/components/chat/ActivityRow.svelte +115 -0
  12. package/dist/components/chat/ActivityRow.svelte.d.ts +18 -0
  13. package/dist/components/chat/ChatHeader.svelte +114 -0
  14. package/dist/components/chat/ChatHeader.svelte.d.ts +26 -0
  15. package/dist/components/chat/Composer.svelte +172 -0
  16. package/dist/components/chat/Composer.svelte.d.ts +27 -0
  17. package/dist/components/chat/Message.svelte +158 -0
  18. package/dist/components/chat/Message.svelte.d.ts +28 -0
  19. package/dist/components/chat/OptionRow.svelte +59 -0
  20. package/dist/components/chat/OptionRow.svelte.d.ts +14 -0
  21. package/dist/components/chat/PlanCard.svelte +220 -0
  22. package/dist/components/chat/PlanCard.svelte.d.ts +34 -0
  23. package/dist/components/chat/QuestionCard.svelte +265 -0
  24. package/dist/components/chat/QuestionCard.svelte.d.ts +38 -0
  25. package/dist/components/chat/ScrollToBottom.svelte +51 -0
  26. package/dist/components/chat/ScrollToBottom.svelte.d.ts +11 -0
  27. package/dist/components/chat/SuggestionCard.svelte +79 -0
  28. package/dist/components/chat/SuggestionCard.svelte.d.ts +20 -0
  29. package/dist/components/chat/TaskRow.svelte +59 -0
  30. package/dist/components/chat/TaskRow.svelte.d.ts +11 -0
  31. package/dist/components/chat/composerLogic.d.ts +16 -0
  32. package/dist/components/chat/composerLogic.js +29 -0
  33. package/dist/components/chat/index.d.ts +16 -0
  34. package/dist/components/chat/index.js +16 -0
  35. package/dist/components/chat/questionCardLogic.d.ts +11 -0
  36. package/dist/components/chat/questionCardLogic.js +39 -0
  37. package/dist/components/index.d.ts +10 -1
  38. package/dist/components/index.js +10 -0
  39. package/dist/components/modals/ActionModal.svelte +186 -180
  40. package/dist/components/modals/BaseModal.svelte +495 -401
  41. package/dist/components/modals/BaseModal.svelte.d.ts +4 -0
  42. package/dist/components/modals/NewItemDialog.svelte +198 -243
  43. package/dist/components/modals/Portal.svelte +109 -105
  44. package/dist/components/modals/README.md +16 -2
  45. package/dist/components/modals/RenameDialog.svelte +232 -292
  46. package/dist/components/modals/modalStore.d.ts +9 -1
  47. package/dist/components/modals/modalStore.js +44 -11
  48. package/dist/components/navigation/Breadcrumbs.svelte +421 -377
  49. package/dist/components/navigation/Breadcrumbs.svelte.d.ts +3 -2
  50. package/dist/components/navigation/breadcrumbsAvailableWidth.d.ts +10 -0
  51. package/dist/components/navigation/breadcrumbsAvailableWidth.js +10 -0
  52. package/dist/components/navigation/types.d.ts +2 -0
  53. package/dist/components/pdf/PDFViewer.svelte +1 -1
  54. package/dist/components/search-input/SearchInput.svelte +63 -104
  55. package/dist/components/search-input/SearchInput.svelte.d.ts +13 -27
  56. package/dist/components/search-input/index2.d.ts +14 -9
  57. package/dist/components/shad-editor/editor.css +1 -1
  58. package/dist/components/shad-editor/i18n/messages.d.ts +1 -1
  59. package/dist/components/shad-editor/i18n/messages.js +1 -1
  60. package/dist/components/shell/AppShell.svelte +52 -0
  61. package/dist/components/shell/AppShell.svelte.d.ts +13 -0
  62. package/dist/components/shell/Banner.svelte +90 -0
  63. package/dist/components/shell/Banner.svelte.d.ts +61 -0
  64. package/dist/components/shell/ErrorState.svelte +60 -0
  65. package/dist/components/shell/ErrorState.svelte.d.ts +13 -0
  66. package/dist/components/shell/Link.svelte +63 -0
  67. package/dist/components/shell/Link.svelte.d.ts +53 -0
  68. package/dist/components/shell/NavDrawer.svelte +117 -0
  69. package/dist/components/shell/NavDrawer.svelte.d.ts +10 -0
  70. package/dist/components/shell/NavRow.svelte +128 -0
  71. package/dist/components/shell/NavRow.svelte.d.ts +65 -0
  72. package/dist/components/shell/NavSectionLabel.svelte +27 -0
  73. package/dist/components/shell/NavSectionLabel.svelte.d.ts +9 -0
  74. package/dist/components/shell/NotificationRow.svelte +76 -0
  75. package/dist/components/shell/NotificationRow.svelte.d.ts +16 -0
  76. package/dist/components/shell/PageHeader.svelte +42 -0
  77. package/dist/components/shell/PageHeader.svelte.d.ts +12 -0
  78. package/dist/components/shell/ProfileRow.svelte +95 -0
  79. package/dist/components/shell/ProfileRow.svelte.d.ts +54 -0
  80. package/dist/components/shell/SettingsDialog.svelte +163 -0
  81. package/dist/components/shell/SettingsDialog.svelte.d.ts +19 -0
  82. package/dist/components/shell/SettingsNav.svelte +46 -0
  83. package/dist/components/shell/SettingsNav.svelte.d.ts +11 -0
  84. package/dist/components/shell/Sidebar.svelte +82 -0
  85. package/dist/components/shell/Sidebar.svelte.d.ts +25 -0
  86. package/dist/components/shell/Stat.svelte +63 -0
  87. package/dist/components/shell/Stat.svelte.d.ts +58 -0
  88. package/dist/components/shell/TopBar.svelte +37 -0
  89. package/dist/components/shell/TopBar.svelte.d.ts +11 -0
  90. package/dist/components/shell/WidgetRow.svelte +126 -0
  91. package/dist/components/shell/WidgetRow.svelte.d.ts +78 -0
  92. package/dist/components/shell/error-state-messages.d.ts +7 -0
  93. package/dist/components/shell/error-state-messages.js +9 -0
  94. package/dist/components/shell/index.d.ts +22 -0
  95. package/dist/components/shell/index.js +25 -0
  96. package/dist/components/shell/link-external.d.ts +2 -0
  97. package/dist/components/shell/link-external.js +7 -0
  98. package/dist/components/shell/messages.d.ts +7 -0
  99. package/dist/components/shell/messages.js +5 -0
  100. package/dist/components/shell/nested-modal-guard.d.ts +25 -0
  101. package/dist/components/shell/nested-modal-guard.js +33 -0
  102. package/dist/components/shell/settings-nav-types.d.ts +12 -0
  103. package/dist/components/shell/settings-nav-types.js +3 -0
  104. package/dist/components/shell/shell-utils.d.ts +7 -0
  105. package/dist/components/shell/shell-utils.js +27 -0
  106. package/dist/components/shell/stat-tone.d.ts +3 -0
  107. package/dist/components/shell/stat-tone.js +11 -0
  108. package/dist/components/toast/ToasterModal.svelte +102 -168
  109. package/dist/components/toast/ToasterModal.svelte.d.ts +2 -12
  110. package/dist/components/ui/accordion/accordion-content.svelte +3 -2
  111. package/dist/components/ui/accordion/accordion-item.svelte +10 -1
  112. package/dist/components/ui/accordion/accordion-trigger.svelte +4 -3
  113. package/dist/components/ui/alert/alert-description.svelte +5 -1
  114. package/dist/components/ui/alert/alert-title.svelte +2 -1
  115. package/dist/components/ui/alert/index.d.ts +13 -11
  116. package/dist/components/ui/alert/index.js +4 -4
  117. package/dist/components/ui/avatar/avatar-utils.d.ts +2 -0
  118. package/dist/components/ui/avatar/avatar-utils.js +9 -0
  119. package/dist/components/ui/avatar/avatar.svelte +63 -0
  120. package/dist/components/ui/avatar/avatar.svelte.d.ts +80 -0
  121. package/dist/components/ui/avatar/index.d.ts +4 -0
  122. package/dist/components/ui/avatar/index.js +4 -0
  123. package/dist/components/ui/badge/badge.svelte +22 -10
  124. package/dist/components/ui/badge/badge.svelte.d.ts +14 -15
  125. package/dist/components/ui/breadcrumb/breadcrumb-ellipsis.svelte +2 -2
  126. package/dist/components/ui/breadcrumb/breadcrumb-link.svelte +1 -1
  127. package/dist/components/ui/breadcrumb/breadcrumb-page.svelte +1 -1
  128. package/dist/components/ui/breadcrumb/breadcrumb-separator.svelte +2 -2
  129. package/dist/components/ui/button/button-padding.d.ts +9 -0
  130. package/dist/components/ui/button/button-padding.js +15 -0
  131. package/dist/components/ui/button/button.svelte +81 -31
  132. package/dist/components/ui/button/button.svelte.d.ts +48 -29
  133. package/dist/components/ui/calendar/calendar-cell.svelte +1 -1
  134. package/dist/components/ui/calendar/calendar-head-cell.svelte +1 -1
  135. package/dist/components/ui/calendar/calendar-next-button.svelte +2 -2
  136. package/dist/components/ui/calendar/calendar-prev-button.svelte +2 -2
  137. package/dist/components/ui/calendar/calendar.svelte.d.ts +1 -1
  138. package/dist/components/ui/card/card-description.svelte +1 -1
  139. package/dist/components/ui/card/card-title.svelte +1 -1
  140. package/dist/components/ui/card/card.svelte +1 -1
  141. package/dist/components/ui/checkbox/checkbox.svelte +9 -5
  142. package/dist/components/ui/chip/chip.svelte +48 -0
  143. package/dist/components/ui/chip/chip.svelte.d.ts +13 -0
  144. package/dist/components/ui/chip/index.d.ts +2 -0
  145. package/dist/components/ui/chip/index.js +2 -0
  146. package/dist/components/ui/command/command-dialog.svelte +1 -1
  147. package/dist/components/ui/command/command-input.svelte +4 -4
  148. package/dist/components/ui/command/command-item.svelte +1 -1
  149. package/dist/components/ui/command/command-link-item.svelte +1 -1
  150. package/dist/components/ui/command/command.svelte +1 -1
  151. package/dist/components/ui/dialog/dialog-content.svelte +11 -4
  152. package/dist/components/ui/dialog/dialog-description.svelte +1 -1
  153. package/dist/components/ui/dialog/dialog-overlay.svelte +8 -1
  154. package/dist/components/ui/dialog/dialog-title.svelte +1 -1
  155. package/dist/components/ui/drawer/drawer-content.svelte +1 -1
  156. package/dist/components/ui/drawer/drawer-overlay.svelte +1 -1
  157. package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +5 -5
  158. package/dist/components/ui/dropdown-menu/dropdown-menu-content.svelte +1 -1
  159. package/dist/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +1 -1
  160. package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte +20 -2
  161. package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte.d.ts +4 -0
  162. package/dist/components/ui/dropdown-menu/dropdown-menu-label.svelte +5 -1
  163. package/dist/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +3 -3
  164. package/dist/components/ui/dropdown-menu/dropdown-menu-separator.svelte +2 -1
  165. package/dist/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +1 -1
  166. package/dist/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +3 -3
  167. package/dist/components/ui/field/field-ids.d.ts +7 -0
  168. package/dist/components/ui/field/field-ids.js +15 -0
  169. package/dist/components/ui/field/field.svelte +62 -0
  170. package/dist/components/ui/field/field.svelte.d.ts +21 -0
  171. package/dist/components/ui/field/index.d.ts +3 -0
  172. package/dist/components/ui/field/index.js +3 -0
  173. package/dist/components/ui/hover-card/hover-card-content.svelte +1 -1
  174. package/dist/components/ui/icon-button/icon-button.svelte +72 -0
  175. package/dist/components/ui/icon-button/icon-button.svelte.d.ts +90 -0
  176. package/dist/components/ui/icon-button/index.d.ts +2 -0
  177. package/dist/components/ui/icon-button/index.js +4 -0
  178. package/dist/components/ui/input/index.d.ts +1 -0
  179. package/dist/components/ui/input/input.svelte +11 -4
  180. package/dist/components/ui/input/input.svelte.d.ts +4 -1
  181. package/dist/components/ui/input-otp/input-otp-separator.svelte +2 -2
  182. package/dist/components/ui/input-otp/input-otp-slot.svelte +5 -4
  183. package/dist/components/ui/input-otp/input-otp-slot.svelte.d.ts +1 -1
  184. package/dist/components/ui/input-otp/input-otp.svelte +1 -1
  185. package/dist/components/ui/label/label.svelte +3 -2
  186. package/dist/components/ui/popover/popover-content.svelte +1 -1
  187. package/dist/components/ui/progress/progress.svelte +19 -5
  188. package/dist/components/ui/progress/progress.svelte.d.ts +4 -2
  189. package/dist/components/ui/radio-group/radio-group-item.svelte +4 -4
  190. package/dist/components/ui/range-calendar/range-calendar-head-cell.svelte +1 -1
  191. package/dist/components/ui/range-calendar/range-calendar-next-button.svelte +2 -2
  192. package/dist/components/ui/range-calendar/range-calendar-prev-button.svelte +2 -2
  193. package/dist/components/ui/range-calendar/range-calendar.svelte.d.ts +1 -1
  194. package/dist/components/ui/scroll-area/scroll-area-scrollbar.svelte +4 -1
  195. package/dist/components/ui/scroll-area/scroll-area.svelte +1 -1
  196. package/dist/components/ui/select/select-content.svelte +1 -3
  197. package/dist/components/ui/select/select-item.svelte +5 -4
  198. package/dist/components/ui/select/select-scroll-down-button.svelte +2 -2
  199. package/dist/components/ui/select/select-scroll-up-button.svelte +2 -2
  200. package/dist/components/ui/select/select-trigger.svelte +4 -3
  201. package/dist/components/ui/skeleton/index.d.ts +2 -0
  202. package/dist/components/ui/skeleton/index.js +2 -0
  203. package/dist/components/ui/skeleton/skeleton.svelte +24 -0
  204. package/dist/components/ui/skeleton/skeleton.svelte.d.ts +8 -0
  205. package/dist/components/ui/slider/slider.svelte +5 -10
  206. package/dist/components/ui/sonner/sonner.svelte +19 -13
  207. package/dist/components/ui/stepper-button/index.d.ts +3 -0
  208. package/dist/components/ui/stepper-button/index.js +2 -0
  209. package/dist/components/ui/stepper-button/stepper-button.svelte +37 -0
  210. package/dist/components/ui/stepper-button/stepper-button.svelte.d.ts +9 -0
  211. package/dist/components/ui/switch/switch.svelte +8 -3
  212. package/dist/components/ui/table/table-cell.svelte +1 -1
  213. package/dist/components/ui/table/table-head.svelte +1 -1
  214. package/dist/components/ui/table/table-row.svelte +1 -1
  215. package/dist/components/ui/tabs/tabs-list.svelte +1 -1
  216. package/dist/components/ui/tabs/tabs-trigger.svelte +1 -1
  217. package/dist/components/ui/tag/index.d.ts +2 -0
  218. package/dist/components/ui/tag/index.js +2 -0
  219. package/dist/components/ui/tag/tag.svelte +42 -0
  220. package/dist/components/ui/tag/tag.svelte.d.ts +11 -0
  221. package/dist/components/ui/textarea/textarea.svelte +4 -3
  222. package/dist/components/ui/textarea/textarea.svelte.d.ts +2 -2
  223. package/dist/components/ui/toggle/toggle.svelte +9 -9
  224. package/dist/components/ui/toggle/toggle.svelte.d.ts +14 -21
  225. package/dist/components/ui/tooltip/tooltip-content.svelte +1 -1
  226. package/dist/fonts/Inter/Inter-Black.woff2 +0 -0
  227. package/dist/fonts/Inter/Inter-BlackItalic.woff2 +0 -0
  228. package/dist/fonts/Inter/Inter-Bold.woff2 +0 -0
  229. package/dist/fonts/Inter/Inter-BoldItalic.woff2 +0 -0
  230. package/dist/fonts/Inter/Inter-ExtraBold.woff2 +0 -0
  231. package/dist/fonts/Inter/Inter-ExtraBoldItalic.woff2 +0 -0
  232. package/dist/fonts/Inter/Inter-ExtraLight-BETA.woff2 +0 -0
  233. package/dist/fonts/Inter/Inter-ExtraLightItalic-BETA.woff2 +0 -0
  234. package/dist/fonts/Inter/Inter-Italic.woff2 +0 -0
  235. package/dist/fonts/Inter/Inter-Light-BETA.woff2 +0 -0
  236. package/dist/fonts/Inter/Inter-LightItalic-BETA.woff2 +0 -0
  237. package/dist/fonts/Inter/Inter-Medium.woff2 +0 -0
  238. package/dist/fonts/Inter/Inter-MediumItalic.woff2 +0 -0
  239. package/dist/fonts/Inter/Inter-Regular.woff2 +0 -0
  240. package/dist/fonts/Inter/Inter-SemiBold.woff2 +0 -0
  241. package/dist/fonts/Inter/Inter-SemiBoldItalic.woff2 +0 -0
  242. package/dist/fonts/Inter/Inter-Thin-BETA.woff2 +0 -0
  243. package/dist/fonts/Inter/Inter-ThinItalic-BETA.woff2 +0 -0
  244. package/dist/fonts/Inter/Inter-italic.var.woff2 +0 -0
  245. package/dist/fonts/Inter/Inter-upright.var.woff2 +0 -0
  246. package/dist/fonts/Inter/Inter.var.woff2 +0 -0
  247. package/dist/fonts/JetBrainsMono/JetBrainsMono-Regular.woff2 +0 -0
  248. package/dist/i18n/audit/designSystemWords.d.ts +1 -1
  249. package/dist/i18n/audit/designSystemWords.js +1 -1
  250. package/dist/styles/fonts.css +18 -14
  251. package/dist/styles/global.css +10 -21
  252. package/dist/styles/tokens.css +332 -0
  253. package/dist/utils/overlayMotion.d.ts +49 -0
  254. package/dist/utils/overlayMotion.js +71 -0
  255. package/dist/utils.d.ts +27 -0
  256. package/dist/utils.js +33 -2
  257. package/package.json +2 -1
  258. package/tailwind.config.ts +7 -47
@@ -1,297 +1,237 @@
1
1
  <script lang="ts">
2
- // Svelte imports
3
- import { createEventDispatcher, tick } from 'svelte';
4
-
5
- // Local imports
6
- import { Button } from '../ui/button';
7
- // import { toast } from '../ui/sonner';
8
- import { showToast } from '../toast';
9
- import BaseModal from './BaseModal.svelte';
10
- // Words of the dialog and the helper that puts values into them
11
- import type { RenameDialogMessages } from './messages';
12
- import { fillMessage } from '../../utils/fillMessage';
13
-
14
- // Props
15
- let className = '';
16
- export { className as class };
17
- export let style: string = '';
18
- //
19
- export let isOpen = false;
20
- export let itemName = '';
21
- export let itemType = 'item'; // 'item', 'folder', 'file', 'key', etc.
22
- export let itemId = '';
23
- export let title = '';
24
- export let placeholder = '';
25
- export let confirmLabel = 'Rename';
26
- export let cancelLabel = 'Cancel';
27
- // The words a screen reader says for the close button (see BaseModal)
28
- export let closeLabel = 'Close modal';
29
- // The words of the errors and toasts; a key that is left out keeps its English text (see ./messages)
30
- export let messages: Partial<RenameDialogMessages> = {};
31
- export let width = '410px';
32
- export let height = '168px';
33
- export let target: string = 'rename-dialog'; // target for Portal
34
- export let maxLength = 50; // Reduced for better UX
35
- export let shouldUseCustomRenameFunction = false; // If true, parent component handles the rename
36
-
37
- // For backwards compatibility with specific implementations
38
- export let modalType: string = 'rename';
39
- export let modalData: any = null;
40
-
41
- let inputValue = '';
42
- let inputElement: HTMLInputElement;
43
- let hasAttemptedSubmit = false; // Track if user has attempted to submit
44
- let isValid = false; // Track if input is valid
45
-
46
- // Initialize modalData with our current props if not provided externally
47
- $: if (modalData === null) {
48
- modalData = {
49
- itemName,
50
- itemType,
51
- itemId,
52
- title,
53
- placeholder,
54
- confirmLabel,
55
- cancelLabel
56
- };
57
- }
58
-
59
- // Update validation state whenever inputValue changes
60
- $: {
61
- isValid = inputValue.trim().length > 0 &&
62
- inputValue.length <= maxLength &&
63
- inputValue !== itemName;
64
- }
65
-
66
- // Computed placeholder based on itemType
67
- $: computedPlaceholder = placeholder || `${itemType} name...`;
68
-
69
- // The words of the errors and toasts: the page's own, or English
70
- $: text = {
71
- invalidTitle: messages.invalidTitle ?? 'Invalid name',
72
- enterName: messages.enterName ?? 'Please enter a name',
73
- enterDifferentName: messages.enterDifferentName ?? 'Please enter a different name',
74
- enterValidName: messages.enterValidName ?? 'Please enter a valid name',
75
- tooShort: messages.tooShort ?? 'Name must be at least 1 character long',
76
- tooLong: fillMessage(messages.tooLong ?? 'Name must be {max} characters or less', { max: maxLength }),
77
- renamed: messages.renamed ?? 'Successfully renamed to {name}',
78
- failed: messages.failed ?? 'Failed to rename item'
79
- };
80
-
81
- // Function to focus and select the input text
82
- async function focusAndSelectInput() {
83
- // Wait for the DOM to update
84
- await tick();
85
-
86
- if (!inputElement) return;
87
-
88
- // Focus the input
89
- inputElement.focus();
90
-
91
- // Select all text
92
- inputElement.setSelectionRange(0, inputElement.value.length);
93
- }
94
-
95
- // Simple function to handle input initialization
96
- function handleInput(event: Event) {
97
- const input = event.target as HTMLInputElement;
98
- inputValue = input.value.slice(0, maxLength);
99
- }
100
-
101
- // When the modal opens, set the input value and focus the input
102
- $: if (isOpen) {
103
- inputValue = itemName;
104
- hasAttemptedSubmit = false; // Reset submission state
105
- // Schedule focus after a short delay
106
- setTimeout(focusAndSelectInput, 50);
107
- }
108
-
109
- const dispatch = createEventDispatcher();
110
-
111
- async function handleRename() {
112
- hasAttemptedSubmit = true;
113
-
114
- try {
115
- // Validate input
116
- if (!inputValue.trim() || inputValue.length < 1) {
117
- showToast('error', text.invalidTitle, { description: text.tooShort });
118
- return;
119
- }
120
-
121
- if (inputValue.length > maxLength) {
122
- showToast('error', text.invalidTitle, { description: text.tooLong });
123
- return;
124
- }
125
-
126
- if (inputValue === itemName) {
127
- showToast('error', text.invalidTitle, { description: text.enterDifferentName });
128
- return;
129
- }
130
-
131
- // console.log('Attempting rename:', {
132
- // from: itemName,
133
- // to: inputValue,
134
- // itemId
135
- // });
136
-
137
- // If parent component handles rename, dispatch event
138
- if (shouldUseCustomRenameFunction) {
139
- dispatch('rename', { itemId, newName: inputValue, oldName: itemName });
140
- isOpen = false;
141
- } else {
142
- // For file browser compatibility - in a real implementation, this would be replaced
143
- // with a more generic approach
144
- try {
145
- // Simulate success
146
- showToast('success', fillMessage(text.renamed, { name: inputValue }));
147
- dispatch('rename', { itemId, newName: inputValue, oldName: itemName });
148
- isOpen = false;
149
- } catch (error) {
150
- console.error('Error during rename:', error);
151
- showToast('error', text.failed);
152
- }
153
- }
154
- } catch (error) {
155
- console.error('Error during rename:', error);
156
- showToast('error', text.failed);
157
- }
158
- }
159
-
160
- function handleClose() {
161
- isOpen = false;
162
- hasAttemptedSubmit = false;
163
- dispatch('cancel');
164
- }
165
-
166
- // Support for restoring modal state
167
- function handleRestore(event: CustomEvent) {
168
- if (event.detail) {
169
- itemName = event.detail.itemName || '';
170
- itemType = event.detail.itemType || 'item';
171
- itemId = event.detail.itemId || '';
172
- if (event.detail.title) title = event.detail.title;
173
- if (event.detail.placeholder) placeholder = event.detail.placeholder;
174
- if (event.detail.confirmLabel) confirmLabel = event.detail.confirmLabel;
175
- if (event.detail.cancelLabel) cancelLabel = event.detail.cancelLabel;
176
-
177
- // Reset input value on restore
178
- inputValue = itemName;
179
-
180
- // Focus and select text when modal is restored
181
- setTimeout(focusAndSelectInput, 50);
182
- }
183
- }
2
+ // Svelte imports
3
+ import { createEventDispatcher, tick } from 'svelte';
4
+
5
+ // Local imports
6
+ import { Button } from '../ui/button';
7
+ import { Input } from '../ui/input';
8
+ import { showToast } from '../toast';
9
+ import BaseModal from './BaseModal.svelte';
10
+ // Words of the dialog and the helper that puts values into them
11
+ import type { RenameDialogMessages } from './messages';
12
+ import { fillMessage } from '../../utils/fillMessage';
13
+
14
+ // Props
15
+ let className = '';
16
+ export { className as class };
17
+ export let style: string = '';
18
+ //
19
+ export let isOpen = false;
20
+ export let itemName = '';
21
+ export let itemType = 'item'; // 'item', 'folder', 'file', 'key', etc.
22
+ export let itemId = '';
23
+ export let title = '';
24
+ export let placeholder = '';
25
+ export let confirmLabel = 'Rename';
26
+ export let cancelLabel = 'Cancel';
27
+ // The words a screen reader says for the close button (see BaseModal)
28
+ export let closeLabel = 'Close modal';
29
+ // The words of the errors and toasts; a key that is left out keeps its English text (see ./messages)
30
+ export let messages: Partial<RenameDialogMessages> = {};
31
+ export let width = '400px';
32
+ export let height = 'auto';
33
+ export let target: string = 'rename-dialog'; // target for Portal
34
+ export let maxLength = 50; // Reduced for better UX
35
+ export let shouldUseCustomRenameFunction = false; // If true, parent component handles the rename
36
+
37
+ // For backwards compatibility with specific implementations
38
+ export let modalType: string = 'rename';
39
+ export let modalData: any = null;
40
+
41
+ let inputValue = '';
42
+ // The Input binds its element to this: it starts as null (an undefined value cannot be bound)
43
+ let inputElement: HTMLInputElement | null = null;
44
+ let hasAttemptedSubmit = false; // Track if user has attempted to submit
45
+ let isValid = false; // Track if input is valid
46
+
47
+ // Initialize modalData with our current props if not provided externally
48
+ $: if (modalData === null) {
49
+ modalData = {
50
+ itemName,
51
+ itemType,
52
+ itemId,
53
+ title,
54
+ placeholder,
55
+ confirmLabel,
56
+ cancelLabel
57
+ };
58
+ }
59
+
60
+ // Update validation state whenever inputValue changes
61
+ $: {
62
+ isValid =
63
+ inputValue.trim().length > 0 && inputValue.length <= maxLength && inputValue !== itemName;
64
+ }
65
+
66
+ // Computed placeholder based on itemType
67
+ $: computedPlaceholder = placeholder || `${itemType} name…`;
68
+
69
+ // The words of the errors and toasts: the page's own, or English
70
+ $: text = {
71
+ invalidTitle: messages.invalidTitle ?? 'Invalid name',
72
+ enterName: messages.enterName ?? 'Please enter a name',
73
+ enterDifferentName: messages.enterDifferentName ?? 'Please enter a different name',
74
+ enterValidName: messages.enterValidName ?? 'Please enter a valid name',
75
+ tooShort: messages.tooShort ?? 'Name must be at least 1 character long',
76
+ tooLong: fillMessage(messages.tooLong ?? 'Name must be {max} characters or less', {
77
+ max: maxLength
78
+ }),
79
+ renamed: messages.renamed ?? 'Successfully renamed to {name}',
80
+ failed: messages.failed ?? 'Failed to rename item'
81
+ };
82
+
83
+ // Function to focus and select the input text
84
+ async function focusAndSelectInput() {
85
+ // Wait for the DOM to update
86
+ await tick();
87
+
88
+ if (!inputElement) return;
89
+
90
+ // Focus the input
91
+ inputElement.focus();
92
+
93
+ // Select all text
94
+ inputElement.setSelectionRange(0, inputElement.value.length);
95
+ }
96
+
97
+ // Simple function to handle input initialization
98
+ function handleInput(event: Event) {
99
+ const input = event.target as HTMLInputElement;
100
+ inputValue = input.value.slice(0, maxLength);
101
+ }
102
+
103
+ // When the modal opens, set the input value and focus the input
104
+ $: if (isOpen) {
105
+ inputValue = itemName;
106
+ hasAttemptedSubmit = false; // Reset submission state
107
+ // Schedule focus after a short delay
108
+ setTimeout(focusAndSelectInput, 50);
109
+ }
110
+
111
+ const dispatch = createEventDispatcher();
112
+
113
+ async function handleRename() {
114
+ hasAttemptedSubmit = true;
115
+
116
+ try {
117
+ // Validate input
118
+ if (!inputValue.trim() || inputValue.length < 1) {
119
+ showToast('error', text.invalidTitle, { description: text.tooShort });
120
+ return;
121
+ }
122
+
123
+ if (inputValue.length > maxLength) {
124
+ showToast('error', text.invalidTitle, { description: text.tooLong });
125
+ return;
126
+ }
127
+
128
+ if (inputValue === itemName) {
129
+ showToast('error', text.invalidTitle, { description: text.enterDifferentName });
130
+ return;
131
+ }
132
+
133
+ // If parent component handles rename, dispatch event
134
+ if (shouldUseCustomRenameFunction) {
135
+ dispatch('rename', { itemId, newName: inputValue, oldName: itemName });
136
+ isOpen = false;
137
+ } else {
138
+ try {
139
+ showToast('success', fillMessage(text.renamed, { name: inputValue }));
140
+ dispatch('rename', { itemId, newName: inputValue, oldName: itemName });
141
+ isOpen = false;
142
+ } catch (error) {
143
+ console.error('Error during rename:', error);
144
+ showToast('error', text.failed);
145
+ }
146
+ }
147
+ } catch (error) {
148
+ console.error('Error during rename:', error);
149
+ showToast('error', text.failed);
150
+ }
151
+ }
152
+
153
+ function handleClose() {
154
+ isOpen = false;
155
+ hasAttemptedSubmit = false;
156
+ dispatch('cancel');
157
+ }
158
+
159
+ // Support for restoring modal state
160
+ function handleRestore(event: CustomEvent) {
161
+ if (event.detail) {
162
+ itemName = event.detail.itemName || '';
163
+ itemType = event.detail.itemType || 'item';
164
+ itemId = event.detail.itemId || '';
165
+ if (event.detail.title) title = event.detail.title;
166
+ if (event.detail.placeholder) placeholder = event.detail.placeholder;
167
+ if (event.detail.confirmLabel) confirmLabel = event.detail.confirmLabel;
168
+ if (event.detail.cancelLabel) cancelLabel = event.detail.cancelLabel;
169
+
170
+ inputValue = itemName;
171
+ setTimeout(focusAndSelectInput, 50);
172
+ }
173
+ }
174
+
175
+ $: displayTitle = title || 'Rename';
176
+ $: validationMessage =
177
+ !isValid && hasAttemptedSubmit
178
+ ? inputValue.trim().length === 0
179
+ ? text.enterName
180
+ : inputValue === itemName
181
+ ? text.enterDifferentName
182
+ : text.enterValidName
183
+ : '';
184
184
  </script>
185
185
 
186
- <BaseModal
187
- bind:open={isOpen}
188
- on:close={handleClose}
189
- {target}
190
- title={title || undefined}
191
- width={width}
192
- height={height}
193
- titlePadding="small"
194
- {closeLabel}
195
- {modalType}
196
- {modalData}
197
- on:restore={handleRestore}
186
+ <BaseModal
187
+ bind:open={isOpen}
188
+ on:close={handleClose}
189
+ {target}
190
+ title={displayTitle}
191
+ {width}
192
+ {height}
193
+ {closeLabel}
194
+ {modalType}
195
+ {modalData}
196
+ on:restore={handleRestore}
198
197
  >
199
- <div class="{className ? `${className} ` : ''}rename-dialog-container h-full flex flex-col gap-4 min-h-[136px] justify-between" style={style}>
200
-
201
- <!-- Input Container -->
202
- <div class="input-container flex flex-col items-center pt-6">
203
- <!-- Simple native input with minimal event handlers -->
204
- <input
205
- type="text"
206
- bind:value={inputValue}
207
- bind:this={inputElement}
208
- oninput={handleInput}
209
- onkeydown={(e) => {
210
- if (e.key === 'Escape') {
211
- handleClose();
212
- } else {
213
- e.stopPropagation(); // Stop all keyboard events except Escape from bubbling up
214
- if (e.key === 'Enter') {
215
- e.preventDefault();
216
- handleRename();
217
- }
218
- }
219
- }}
220
- onfocus={(e) => {
221
- const target = e.target as HTMLInputElement;
222
- target.placeholder = "";
223
-
224
- // Select all text
225
- setTimeout(() => {
226
- if (target) {
227
- target.setSelectionRange(0, target.value.length);
228
- }
229
- }, 0);
230
- }}
231
- onblur={(e) => {
232
- const target = e.target as HTMLInputElement;
233
- target.placeholder = computedPlaceholder;
234
- }}
235
- required
236
- class="w-full h5 text-[24px] text-[hsl(var(--grey7))] text-center
237
- bg-transparent border-none focus:outline-hidden focus:ring-0
238
- placeholder:text-[24px] placeholder:text-[hsl(var(--grey3))]
239
- text-ellipsis-input
240
- {!isValid && hasAttemptedSubmit ? 'input-error' : ''}"
241
- maxlength={maxLength}
242
- data-min-length="1"
243
- placeholder={computedPlaceholder}
244
- />
245
- {#if !isValid && hasAttemptedSubmit}
246
- <div class="text-xs text-[hsl(var(--error))] mt-1">
247
- {inputValue.trim().length === 0 ? text.enterName :
248
- inputValue === itemName ? text.enterDifferentName :
249
- text.enterValidName}
250
- </div>
251
- {/if}
252
- </div>
253
-
254
- <!-- Buttons Container -->
255
- <div class="buttons-container flex justify-center gap-4">
256
- <!-- Cancel Button -->
257
- <!-- svelte-ignore a11y-no-static-element-interactions -->
258
- <Button
259
- class="modal-btn-secondary !h-[34px]"
260
- onclick={handleClose}
261
- >
262
- {cancelLabel}
263
- </Button>
264
-
265
- <!-- Confirm Button -->
266
- <Button
267
- class="modal-btn-primary !h-[34px]"
268
- onclick={handleRename}
269
- disabled={!isValid}
270
- >
271
- {confirmLabel}
272
- </Button>
273
- </div>
274
- </div>
198
+ <div
199
+ class="{className ? `${className} ` : ''}rename-dialog-container flex flex-col gap-4"
200
+ {style}
201
+ >
202
+ <div class="flex flex-col gap-1.5">
203
+ <Input
204
+ bind:ref={inputElement}
205
+ bind:value={inputValue}
206
+ placeholder={computedPlaceholder}
207
+ maxlength={maxLength}
208
+ aria-invalid={Boolean(validationMessage)}
209
+ class={validationMessage ? 'border-destructive' : ''}
210
+ oninput={handleInput}
211
+ onkeydown={(e) => {
212
+ if (e.key !== 'Escape') {
213
+ e.stopPropagation();
214
+ }
215
+ if (e.key === 'Enter') {
216
+ e.preventDefault();
217
+ handleRename();
218
+ }
219
+ }}
220
+ onfocus={(e) => {
221
+ const target = e.currentTarget;
222
+ setTimeout(() => {
223
+ target.setSelectionRange(0, target.value.length);
224
+ }, 0);
225
+ }}
226
+ />
227
+ {#if validationMessage}
228
+ <p class="text-caption text-destructive">{validationMessage}</p>
229
+ {/if}
230
+ </div>
231
+
232
+ <div class="flex justify-end gap-2">
233
+ <Button variant="outline" onclick={handleClose}>{cancelLabel}</Button>
234
+ <Button onclick={handleRename} disabled={!isValid}>{confirmLabel}</Button>
235
+ </div>
236
+ </div>
275
237
  </BaseModal>
276
-
277
- <style>
278
- :global(.input-error) {
279
- animation: shake 0.4s ease-in-out;
280
- border-bottom: 1px solid hsl(var(--error)) !important;
281
- }
282
-
283
- :global(.text-ellipsis-input) {
284
- overflow: hidden;
285
- text-overflow: ellipsis;
286
- white-space: nowrap;
287
- max-width: 100%;
288
- padding: 0 16px; /* Add padding to prevent text from touching edges */
289
- box-sizing: border-box;
290
- }
291
-
292
- @keyframes shake {
293
- 0%, 100% { transform: translateX(0); }
294
- 25% { transform: translateX(-5px); }
295
- 75% { transform: translateX(5px); }
296
- }
297
- </style>
@@ -1,10 +1,18 @@
1
1
  interface ModalState {
2
2
  isOpen: boolean;
3
+ /** Top-most open modal generation; used with `openModal` / `closeModal` for restore and global `modalState`. */
4
+ generation?: number;
3
5
  modalType?: string;
4
6
  data?: any;
5
7
  }
6
8
  export declare const modalState: import("svelte/store").Writable<ModalState>;
7
9
  export declare const isModalOpen: import("svelte/store").Writable<boolean>;
8
- export declare function openModal(modalType?: string, data?: any): void;
10
+ export declare function openModal(modalType?: string, data?: any): number;
9
11
  export declare function closeModal(): void;
12
+ /** Call when a BaseModal instance opens — returns an opaque token used with `isTopModalInstance` / `unregisterModalInstance`. */
13
+ export declare function registerModalInstance(): symbol;
14
+ /** Remove this instance from the stack (e.g. closed or destroyed). Safe if already removed. */
15
+ export declare function unregisterModalInstance(token: symbol): void;
16
+ /** True when this instance should handle backdrop / Escape while several modals are stacked. */
17
+ export declare function isTopModalInstance(token: symbol): boolean;
10
18
  export {};
@@ -1,7 +1,4 @@
1
1
  import { writable } from 'svelte/store';
2
- // import { browser } from '$app/environment';
3
- // Determine if running in browser (avoids reference errors during SSR)
4
- const browser = typeof window !== 'undefined';
5
2
  // Debug flag – set to true when you need to trace modal behaviour
6
3
  const showLogs = false;
7
4
  /*
@@ -12,26 +9,62 @@ const showLogs = false;
12
9
  * clean slate after any refresh.
13
10
  */
14
11
  // Always start with a closed modal on fresh page loads
15
- const getInitialState = () => ({ isOpen: false });
12
+ const getInitialState = () => ({ isOpen: false, generation: 0 });
16
13
  // Central writable store for runtime modal state
17
14
  export const modalState = writable(getInitialState());
18
15
  // Backwards-compatibility helper – exposes only the boolean flag
19
16
  export const isModalOpen = writable(getInitialState().isOpen);
20
17
  // Keep `isModalOpen` in sync (without persisting to localStorage)
21
- modalState.subscribe(state => {
18
+ modalState.subscribe((state) => {
22
19
  // if (showLogs) console.log('Modal state updated:', state);
23
20
  isModalOpen.set(state.isOpen);
24
21
  });
22
+ let generationCounter = 0;
23
+ const openStack = [];
24
+ /** Which BaseModal instance is top-most for backdrop + Escape (independent of `generation` timing). */
25
+ const modalInstanceStack = [];
26
+ function syncStoreFromStack() {
27
+ const top = openStack[openStack.length - 1];
28
+ if (!top) {
29
+ modalState.set(getInitialState());
30
+ }
31
+ else {
32
+ modalState.set({
33
+ isOpen: true,
34
+ generation: top.generation,
35
+ modalType: top.modalType,
36
+ data: top.data
37
+ });
38
+ }
39
+ }
25
40
  // Helper functions to manage modal state
26
41
  export function openModal(modalType, data) {
27
42
  // if (showLogs) console.log('Opening modal:', { modalType, data });
28
- modalState.set({
29
- isOpen: true,
30
- modalType,
31
- data,
32
- });
43
+ generationCounter += 1;
44
+ const entry = { generation: generationCounter, modalType, data };
45
+ openStack.push(entry);
46
+ syncStoreFromStack();
47
+ return entry.generation;
33
48
  }
34
49
  export function closeModal() {
35
50
  // if (showLogs) console.log('Closing modal');
36
- modalState.set({ isOpen: false });
51
+ openStack.pop();
52
+ syncStoreFromStack();
53
+ }
54
+ /** Call when a BaseModal instance opens — returns an opaque token used with `isTopModalInstance` / `unregisterModalInstance`. */
55
+ export function registerModalInstance() {
56
+ const token = Symbol('base-modal-instance');
57
+ modalInstanceStack.push(token);
58
+ return token;
59
+ }
60
+ /** Remove this instance from the stack (e.g. closed or destroyed). Safe if already removed. */
61
+ export function unregisterModalInstance(token) {
62
+ const idx = modalInstanceStack.lastIndexOf(token);
63
+ if (idx >= 0)
64
+ modalInstanceStack.splice(idx, 1);
65
+ }
66
+ /** True when this instance should handle backdrop / Escape while several modals are stacked. */
67
+ export function isTopModalInstance(token) {
68
+ const n = modalInstanceStack.length;
69
+ return n > 0 && modalInstanceStack[n - 1] === token;
37
70
  }