@warkypublic/svelix 0.1.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 (212) hide show
  1. package/LICENSE +73 -0
  2. package/README.md +3 -0
  3. package/dist/actions/index.d.ts +1 -0
  4. package/dist/actions/index.js +2 -0
  5. package/dist/components/BetterMenu/BetterMenu.stories.js +68 -0
  6. package/dist/components/BetterMenu/BetterMenu.svelte +38 -0
  7. package/dist/components/BetterMenu/BetterMenu.svelte.d.ts +14 -0
  8. package/dist/components/BetterMenu/BetterMenuAsyncButton.svelte +34 -0
  9. package/dist/components/BetterMenu/BetterMenuAsyncButton.svelte.d.ts +8 -0
  10. package/dist/components/BetterMenu/BetterMenuPreview.svelte +43 -0
  11. package/dist/components/BetterMenu/BetterMenuPreview.svelte.d.ts +7 -0
  12. package/dist/components/BetterMenu/MenuRenderer.svelte +75 -0
  13. package/dist/components/BetterMenu/MenuRenderer.svelte.d.ts +6 -0
  14. package/dist/components/BetterMenu/Plan.mdx +155 -0
  15. package/dist/components/BetterMenu/index.d.ts +4 -0
  16. package/dist/components/BetterMenu/index.js +4 -0
  17. package/dist/components/BetterMenu/store.d.ts +10 -0
  18. package/dist/components/BetterMenu/store.js +48 -0
  19. package/dist/components/BetterMenu/types.d.ts +24 -0
  20. package/dist/components/BetterMenu/types.js +1 -0
  21. package/dist/components/Boxer/Boxer.stories.d.ts +19 -0
  22. package/dist/components/Boxer/Boxer.stories.js +102 -0
  23. package/dist/components/Boxer/Boxer.svelte +411 -0
  24. package/dist/components/Boxer/Boxer.svelte.d.ts +11 -0
  25. package/dist/components/Boxer/BoxerTarget.svelte +88 -0
  26. package/dist/components/Boxer/BoxerTarget.svelte.d.ts +20 -0
  27. package/dist/components/Boxer/Plan.mdx +140 -0
  28. package/dist/components/Boxer/features.mdx +81 -0
  29. package/dist/components/Boxer/index.d.ts +4 -0
  30. package/dist/components/Boxer/index.js +4 -0
  31. package/dist/components/Boxer/store.d.ts +26 -0
  32. package/dist/components/Boxer/store.js +103 -0
  33. package/dist/components/Boxer/types.d.ts +46 -0
  34. package/dist/components/Boxer/types.js +1 -0
  35. package/dist/components/Button.stories.d.ts +11 -0
  36. package/dist/components/Button.stories.js +109 -0
  37. package/dist/components/Button.svelte +50 -0
  38. package/dist/components/Button.svelte.d.ts +12 -0
  39. package/dist/components/ButtonPreview.svelte +14 -0
  40. package/dist/components/ButtonPreview.svelte.d.ts +4 -0
  41. package/dist/components/ErrorBoundary/ErrorBoundary.stories.js +17 -0
  42. package/dist/components/ErrorBoundary/ErrorBoundary.svelte +127 -0
  43. package/dist/components/ErrorBoundary/ErrorBoundary.svelte.d.ts +13 -0
  44. package/dist/components/ErrorBoundary/ErrorBoundaryPreview.svelte +28 -0
  45. package/dist/components/ErrorBoundary/ErrorBoundaryPreview.svelte.d.ts +6 -0
  46. package/dist/components/ErrorBoundary/ErrorManager.d.ts +15 -0
  47. package/dist/components/ErrorBoundary/ErrorManager.js +158 -0
  48. package/dist/components/ErrorBoundary/Plan.mdx +182 -0
  49. package/dist/components/ErrorBoundary/index.d.ts +3 -0
  50. package/dist/components/ErrorBoundary/index.js +3 -0
  51. package/dist/components/ErrorBoundary/types.d.ts +43 -0
  52. package/dist/components/ErrorBoundary/types.js +1 -0
  53. package/dist/components/Former/Former.stories.js +228 -0
  54. package/dist/components/Former/Former.svelte +405 -0
  55. package/dist/components/Former/Former.svelte.d.ts +33 -0
  56. package/dist/components/Former/FormerButtonArea.svelte +93 -0
  57. package/dist/components/Former/FormerButtonArea.svelte.d.ts +15 -0
  58. package/dist/components/Former/FormerDrawer.svelte +115 -0
  59. package/dist/components/Former/FormerDrawer.svelte.d.ts +19 -0
  60. package/dist/components/Former/FormerDrawerPreview.svelte +226 -0
  61. package/dist/components/Former/FormerDrawerPreview.svelte.d.ts +7 -0
  62. package/dist/components/Former/FormerModal.svelte +108 -0
  63. package/dist/components/Former/FormerModal.svelte.d.ts +14 -0
  64. package/dist/components/Former/FormerModalPreview.svelte +226 -0
  65. package/dist/components/Former/FormerModalPreview.svelte.d.ts +7 -0
  66. package/dist/components/Former/FormerPreview.svelte +238 -0
  67. package/dist/components/Former/FormerPreview.svelte.d.ts +8 -0
  68. package/dist/components/Former/FormerResolveSpecAPI.d.ts +26 -0
  69. package/dist/components/Former/FormerResolveSpecAPI.js +44 -0
  70. package/dist/components/Former/FormerRestApiPreview.svelte +198 -0
  71. package/dist/components/Former/FormerRestApiPreview.svelte.d.ts +3 -0
  72. package/dist/components/Former/FormerRestHeadSpecAPI.d.ts +8 -0
  73. package/dist/components/Former/FormerRestHeadSpecAPI.js +38 -0
  74. package/dist/components/Former/Plan.mdx +115 -0
  75. package/dist/components/Former/formerState.svelte.d.ts +21 -0
  76. package/dist/components/Former/formerState.svelte.js +57 -0
  77. package/dist/components/Former/index.d.ts +8 -0
  78. package/dist/components/Former/index.js +8 -0
  79. package/dist/components/Former/types.d.ts +61 -0
  80. package/dist/components/Former/types.js +1 -0
  81. package/dist/components/FormerControllers/ButtonCtrl.stories.js +102 -0
  82. package/dist/components/FormerControllers/ButtonCtrl.svelte +65 -0
  83. package/dist/components/FormerControllers/ButtonCtrl.svelte.d.ts +14 -0
  84. package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrl.stories.js +73 -0
  85. package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrl.svelte +630 -0
  86. package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrl.svelte.d.ts +54 -0
  87. package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrl.utils.d.ts +40 -0
  88. package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrl.utils.js +688 -0
  89. package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrlCalendar.svelte +193 -0
  90. package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrlCalendar.svelte.d.ts +13 -0
  91. package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrlPickerPanel.svelte +119 -0
  92. package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrlPickerPanel.svelte.d.ts +39 -0
  93. package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrlTimeFields.svelte +343 -0
  94. package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrlTimeFields.svelte.d.ts +27 -0
  95. package/dist/components/FormerControllers/DateTimeCtrl/index.d.ts +2 -0
  96. package/dist/components/FormerControllers/DateTimeCtrl/index.js +1 -0
  97. package/dist/components/FormerControllers/FormerControllers.stories.js +76 -0
  98. package/dist/components/FormerControllers/IconButtonCtrl.stories.js +77 -0
  99. package/dist/components/FormerControllers/IconButtonCtrl.svelte +64 -0
  100. package/dist/components/FormerControllers/IconButtonCtrl.svelte.d.ts +13 -0
  101. package/dist/components/FormerControllers/InlineWrapper.stories.js +133 -0
  102. package/dist/components/FormerControllers/InlineWrapper.svelte +85 -0
  103. package/dist/components/FormerControllers/InlineWrapper.svelte.d.ts +16 -0
  104. package/dist/components/FormerControllers/InlineWrapperPreview.svelte +41 -0
  105. package/dist/components/FormerControllers/InlineWrapperPreview.svelte.d.ts +13 -0
  106. package/dist/components/FormerControllers/NativeSelectCtrl.stories.js +79 -0
  107. package/dist/components/FormerControllers/NativeSelectCtrl.svelte +61 -0
  108. package/dist/components/FormerControllers/NativeSelectCtrl.svelte.d.ts +13 -0
  109. package/dist/components/FormerControllers/NumberInputCtrl.stories.js +77 -0
  110. package/dist/components/FormerControllers/NumberInputCtrl.svelte +61 -0
  111. package/dist/components/FormerControllers/NumberInputCtrl.svelte.d.ts +11 -0
  112. package/dist/components/FormerControllers/PasswordInputCtrl.stories.js +79 -0
  113. package/dist/components/FormerControllers/PasswordInputCtrl.svelte +57 -0
  114. package/dist/components/FormerControllers/PasswordInputCtrl.svelte.d.ts +8 -0
  115. package/dist/components/FormerControllers/Plan.mdx +129 -0
  116. package/dist/components/FormerControllers/SwitchCtrl.stories.js +73 -0
  117. package/dist/components/FormerControllers/SwitchCtrl.svelte +38 -0
  118. package/dist/components/FormerControllers/SwitchCtrl.svelte.d.ts +8 -0
  119. package/dist/components/FormerControllers/TextAreaCtrl.stories.js +71 -0
  120. package/dist/components/FormerControllers/TextAreaCtrl.svelte +47 -0
  121. package/dist/components/FormerControllers/TextAreaCtrl.svelte.d.ts +9 -0
  122. package/dist/components/FormerControllers/TextInputCtrl.svelte +47 -0
  123. package/dist/components/FormerControllers/TextInputCtrl.svelte.d.ts +9 -0
  124. package/dist/components/FormerControllers/index.d.ts +12 -0
  125. package/dist/components/FormerControllers/index.js +11 -0
  126. package/dist/components/FormerControllers/types.d.ts +10 -0
  127. package/dist/components/FormerControllers/types.js +1 -0
  128. package/dist/components/GlobalStateStore/GlobalStateStore.d.ts +19 -0
  129. package/dist/components/GlobalStateStore/GlobalStateStore.js +349 -0
  130. package/dist/components/GlobalStateStore/GlobalStateStore.types.d.ts +127 -0
  131. package/dist/components/GlobalStateStore/GlobalStateStore.types.js +2 -0
  132. package/dist/components/GlobalStateStore/GlobalStateStore.utils.d.ts +4 -0
  133. package/dist/components/GlobalStateStore/GlobalStateStore.utils.js +92 -0
  134. package/dist/components/GlobalStateStore/GlobalStateStoreContext.d.ts +10 -0
  135. package/dist/components/GlobalStateStore/GlobalStateStoreContext.js +10 -0
  136. package/dist/components/GlobalStateStore/GlobalStateStoreProvider.svelte +113 -0
  137. package/dist/components/GlobalStateStore/GlobalStateStoreProvider.svelte.d.ts +16 -0
  138. package/dist/components/GlobalStateStore/index.d.ts +5 -0
  139. package/dist/components/GlobalStateStore/index.js +3 -0
  140. package/dist/components/Gridler/CellEditor.svelte +126 -0
  141. package/dist/components/Gridler/CellEditor.svelte.d.ts +15 -0
  142. package/dist/components/Gridler/Gridler.stories.d.ts +56 -0
  143. package/dist/components/Gridler/Gridler.stories.js +262 -0
  144. package/dist/components/Gridler/Gridler.svelte +778 -0
  145. package/dist/components/Gridler/Gridler.svelte.d.ts +11 -0
  146. package/dist/components/Gridler/GridlerHeader.svelte +179 -0
  147. package/dist/components/Gridler/GridlerHeader.svelte.d.ts +13 -0
  148. package/dist/components/Gridler/Plan.mdx +692 -0
  149. package/dist/components/Gridler/index.d.ts +6 -0
  150. package/dist/components/Gridler/index.js +6 -0
  151. package/dist/components/Gridler/types.d.ts +84 -0
  152. package/dist/components/Gridler/types.js +16 -0
  153. package/dist/components/Gridler/utils/rendering.d.ts +16 -0
  154. package/dist/components/Gridler/utils/rendering.js +202 -0
  155. package/dist/components/Gridler/utils/scrolling.d.ts +12 -0
  156. package/dist/components/Gridler/utils/scrolling.js +97 -0
  157. package/dist/components/Portal/Portal.mdx +125 -0
  158. package/dist/components/Portal/Portal.svelte +47 -0
  159. package/dist/components/Portal/Portal.svelte.d.ts +18 -0
  160. package/dist/components/Screenshot/Screenshot.stories.d.ts +16 -0
  161. package/dist/components/Screenshot/Screenshot.stories.js +15 -0
  162. package/dist/components/Screenshot/Screenshot.svelte +54 -0
  163. package/dist/components/Screenshot/Screenshot.svelte.d.ts +3 -0
  164. package/dist/components/Screenshot/Screenshot.util.d.ts +1 -0
  165. package/dist/components/Screenshot/Screenshot.util.js +49 -0
  166. package/dist/components/Screenshot/index.d.ts +2 -0
  167. package/dist/components/Screenshot/index.js +2 -0
  168. package/dist/components/Svark/Svark.stories.js +659 -0
  169. package/dist/components/Svark/Svark.svelte +691 -0
  170. package/dist/components/Svark/Svark.svelte.d.ts +26 -0
  171. package/dist/components/Svark/SvarkResolveSpecAdapter.d.ts +16 -0
  172. package/dist/components/Svark/SvarkResolveSpecAdapter.js +68 -0
  173. package/dist/components/Svark/SvarkSelectionDemo.svelte +59 -0
  174. package/dist/components/Svark/SvarkSelectionDemo.svelte.d.ts +4 -0
  175. package/dist/components/Svark/index.d.ts +3 -0
  176. package/dist/components/Svark/index.js +3 -0
  177. package/dist/components/Svark/types.d.ts +63 -0
  178. package/dist/components/Svark/types.js +1 -0
  179. package/dist/components/VTree/VTree.models.d.ts +12 -0
  180. package/dist/components/VTree/VTree.models.js +1 -0
  181. package/dist/components/VTree/VTree.stories.d.ts +40 -0
  182. package/dist/components/VTree/VTree.stories.js +112 -0
  183. package/dist/components/VTree/VTree.svelte +471 -0
  184. package/dist/components/VTree/VTree.svelte.d.ts +5 -0
  185. package/dist/components/VTree/VTreeContextMenu.svelte +40 -0
  186. package/dist/components/VTree/VTreeContextMenu.svelte.d.ts +11 -0
  187. package/dist/components/VTree/VTreeEventsDemo.svelte +88 -0
  188. package/dist/components/VTree/VTreeEventsDemo.svelte.d.ts +3 -0
  189. package/dist/components/VTree/VTreeResolveSpecAdapter.d.ts +14 -0
  190. package/dist/components/VTree/VTreeResolveSpecAdapter.js +103 -0
  191. package/dist/components/VTree/VTreeRow.svelte +136 -0
  192. package/dist/components/VTree/VTreeRow.svelte.d.ts +37 -0
  193. package/dist/components/VTree/VTreeSearch.svelte +25 -0
  194. package/dist/components/VTree/VTreeSearch.svelte.d.ts +8 -0
  195. package/dist/components/VTree/VTreeVirtualViewport.svelte +154 -0
  196. package/dist/components/VTree/VTreeVirtualViewport.svelte.d.ts +45 -0
  197. package/dist/components/VTree/index.d.ts +3 -0
  198. package/dist/components/VTree/index.js +3 -0
  199. package/dist/components/VTree/types.d.ts +83 -0
  200. package/dist/components/VTree/types.js +1 -0
  201. package/dist/components/index.d.ts +11 -0
  202. package/dist/components/index.js +11 -0
  203. package/dist/index.d.ts +16 -0
  204. package/dist/index.js +20 -0
  205. package/dist/stores/index.d.ts +1 -0
  206. package/dist/stores/index.js +1 -0
  207. package/dist/themes/svelix_orange.css +205 -0
  208. package/dist/utils/PropsWithChildren.d.ts +5 -0
  209. package/dist/utils/PropsWithChildren.js +1 -0
  210. package/dist/utils/index.d.ts +1 -0
  211. package/dist/utils/index.js +2 -0
  212. package/package.json +85 -0
@@ -0,0 +1,93 @@
1
+ <script lang="ts">
2
+ import type { FormRequestType } from "./types";
3
+
4
+ interface Props {
5
+ closeButtonTitle?: string;
6
+ dirty?: boolean;
7
+ keepOpen?: boolean;
8
+ onClose?: () => void;
9
+ onSave?: () => Promise<void>;
10
+ onToggleKeepOpen?: (checked: boolean) => void;
11
+ request?: FormRequestType;
12
+ saveButtonTitle?: string;
13
+ showKeepOpenSwitch?: boolean;
14
+ }
15
+
16
+ const {
17
+ closeButtonTitle = "Close",
18
+ dirty,
19
+ keepOpen,
20
+ onClose,
21
+ onSave,
22
+ onToggleKeepOpen,
23
+ request,
24
+ saveButtonTitle = "Save",
25
+ showKeepOpenSwitch,
26
+ }: Props = $props();
27
+
28
+ const disabledSave = $derived(
29
+ ["select", "view"].includes(request ?? "") ||
30
+ (["update"].includes(request ?? "") && !dirty),
31
+ );
32
+
33
+ const saveTooltip = $derived(
34
+ disabledSave
35
+ ? "Cannot save in view or select mode, or no changes made."
36
+ : "Save the current record",
37
+ );
38
+
39
+ const saveBtnClass = $derived(
40
+ request === "delete"
41
+ ? "preset-filled-error-token"
42
+ : "preset-filled-primary-500",
43
+ );
44
+
45
+ let saving = $state(false);
46
+
47
+ async function handleSave() {
48
+ if (!onSave) return;
49
+ saving = true;
50
+ try {
51
+ await onSave();
52
+ } finally {
53
+ saving = false;
54
+ }
55
+ }
56
+ </script>
57
+
58
+ <div
59
+ class="flex items-center justify-center gap-2 p-2 shadow-sm w-full flex-wrap"
60
+ >
61
+ {#if typeof onClose === "function"}
62
+ <button
63
+ class="btn preset-filled-secondary-500 min-w-32"
64
+ type="button"
65
+ onclick={onClose}
66
+ >
67
+ ✕ {closeButtonTitle}
68
+ </button>
69
+ {/if}
70
+
71
+ {#if showKeepOpenSwitch}
72
+ <label class="flex items-center gap-2 text-sm">
73
+ <input
74
+ checked={keepOpen}
75
+ class="checkbox"
76
+ type="checkbox"
77
+ onchange={(e) => onToggleKeepOpen?.(e.currentTarget.checked)}
78
+ />
79
+ Keep Open
80
+ </label>
81
+ {/if}
82
+
83
+ <button
84
+ class="btn {saveBtnClass} min-w-32"
85
+ disabled={disabledSave || saving}
86
+ title={saveTooltip}
87
+ type="button"
88
+ onclick={handleSave}
89
+ >
90
+ {#if saving}<span class="animate-spin mr-1">⟳</span>{/if}
91
+ 💾 {saveButtonTitle}
92
+ </button>
93
+ </div>
@@ -0,0 +1,15 @@
1
+ import type { FormRequestType } from "./types";
2
+ interface Props {
3
+ closeButtonTitle?: string;
4
+ dirty?: boolean;
5
+ keepOpen?: boolean;
6
+ onClose?: () => void;
7
+ onSave?: () => Promise<void>;
8
+ onToggleKeepOpen?: (checked: boolean) => void;
9
+ request?: FormRequestType;
10
+ saveButtonTitle?: string;
11
+ showKeepOpenSwitch?: boolean;
12
+ }
13
+ declare const FormerButtonArea: import("svelte").Component<Props, {}, "">;
14
+ type FormerButtonArea = ReturnType<typeof FormerButtonArea>;
15
+ export default FormerButtonArea;
@@ -0,0 +1,115 @@
1
+ <script lang="ts">
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
3
+ import { Dialog, Portal } from '@skeletonlabs/skeleton-svelte';
4
+ import Former from './Former.svelte';
5
+ import type { FormerProps, FormRequestType } from './types';
6
+
7
+ interface Props extends FormerProps {
8
+ /**
9
+ * Override the auto-generated drawer title.
10
+ * When omitted the title is derived from the request type and the unique key value:
11
+ * insert → "New Record"
12
+ * update → "Edit Record — {key}"
13
+ * delete → "Delete Record — {key}"
14
+ */
15
+ title?: string;
16
+ /**
17
+ * Width of the drawer panel.
18
+ * @default '32rem'
19
+ */
20
+ width?: string;
21
+ }
22
+
23
+ let {
24
+ afterGet,
25
+ afterSave,
26
+ beforeSave,
27
+ children,
28
+ id,
29
+ keepOpen = $bindable(false),
30
+ layout,
31
+ onAPICall,
32
+ onChange,
33
+ onClose,
34
+ onConfirmDelete,
35
+ onError,
36
+ onOpen,
37
+ opened = $bindable(false),
38
+ primeData,
39
+ request = $bindable<FormRequestType>('insert'),
40
+ title,
41
+ uniqueKeyField = 'id',
42
+ values = $bindable<any>(undefined),
43
+ width = '32rem',
44
+ }: Props = $props();
45
+
46
+ const autoTitle = $derived(
47
+ title ??
48
+ (request === 'delete'
49
+ ? `Delete Record${(values as any)?.[uniqueKeyField] ? ` — ${(values as any)[uniqueKeyField]}` : ''}`
50
+ : request === 'insert'
51
+ ? 'New Record'
52
+ : `Edit Record${(values as any)?.[uniqueKeyField] ? ` — ${(values as any)[uniqueKeyField]}` : ''}`)
53
+ );
54
+
55
+ const animBackdrop =
56
+ 'transition transition-discrete opacity-0 starting:data-[state=open]:opacity-0 data-[state=open]:opacity-100';
57
+ const animContent =
58
+ 'transition transition-discrete opacity-0 translate-x-full starting:data-[state=open]:opacity-0 starting:data-[state=open]:translate-x-full data-[state=open]:opacity-100 data-[state=open]:translate-x-0';
59
+ </script>
60
+
61
+ <Dialog
62
+ open={opened}
63
+ onOpenChange={(e) => {
64
+ opened = e.open;
65
+ if (!e.open) onClose?.();
66
+ }}
67
+ closeOnInteractOutside={false}
68
+ closeOnEscape={false}
69
+ modal
70
+ >
71
+ <Portal>
72
+ <Dialog.Backdrop class="fixed inset-0 z-40 bg-black/50 backdrop-blur-sm {animBackdrop}" />
73
+ <Dialog.Positioner class="fixed inset-0 z-50 flex justify-end">
74
+ <Dialog.Content
75
+ class="card bg-surface-100-900 shadow-2xl h-full flex flex-col overflow-hidden rounded-none rounded-l-container-token {animContent}"
76
+ style="width: {width}"
77
+ >
78
+ <header
79
+ class="flex items-center justify-between px-6 pt-5 pb-4 border-b border-surface-300-600 shrink-0"
80
+ >
81
+ <Dialog.Title class="text-lg font-semibold">{autoTitle}</Dialog.Title>
82
+ <Dialog.CloseTrigger class="btn-icon btn-icon-sm preset-tonal" aria-label="Close drawer">
83
+
84
+ </Dialog.CloseTrigger>
85
+ </header>
86
+
87
+ <div class="flex-1 min-h-0 overflow-auto">
88
+ <Former
89
+ bind:values
90
+ bind:opened
91
+ bind:request
92
+ bind:keepOpen
93
+ {afterGet}
94
+ {afterSave}
95
+ {beforeSave}
96
+ {children}
97
+ {id}
98
+ layout={{ buttonArea: 'bottom', ...layout }}
99
+ {onAPICall}
100
+ {onChange}
101
+ {onConfirmDelete}
102
+ {onError}
103
+ {onOpen}
104
+ {primeData}
105
+ {uniqueKeyField}
106
+ onClose={(data) => {
107
+ opened = false;
108
+ onClose?.(data);
109
+ }}
110
+ />
111
+ </div>
112
+ </Dialog.Content>
113
+ </Dialog.Positioner>
114
+ </Portal>
115
+ </Dialog>
@@ -0,0 +1,19 @@
1
+ import type { FormerProps } from './types';
2
+ interface Props extends FormerProps {
3
+ /**
4
+ * Override the auto-generated drawer title.
5
+ * When omitted the title is derived from the request type and the unique key value:
6
+ * insert → "New Record"
7
+ * update → "Edit Record — {key}"
8
+ * delete → "Delete Record — {key}"
9
+ */
10
+ title?: string;
11
+ /**
12
+ * Width of the drawer panel.
13
+ * @default '32rem'
14
+ */
15
+ width?: string;
16
+ }
17
+ declare const FormerDrawer: import("svelte").Component<Props, {}, "values" | "opened" | "request" | "keepOpen">;
18
+ type FormerDrawer = ReturnType<typeof FormerDrawer>;
19
+ export default FormerDrawer;
@@ -0,0 +1,226 @@
1
+ <script lang="ts">
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
3
+ import FormerDrawer from './FormerDrawer.svelte';
4
+ import type { FormRequestType } from './types';
5
+ import TextInputCtrl from '../FormerControllers/TextInputCtrl.svelte';
6
+ import PasswordInputCtrl from '../FormerControllers/PasswordInputCtrl.svelte';
7
+ import NumberInputCtrl from '../FormerControllers/NumberInputCtrl.svelte';
8
+ import NativeSelectCtrl from '../FormerControllers/NativeSelectCtrl.svelte';
9
+ import TextAreaCtrl from '../FormerControllers/TextAreaCtrl.svelte';
10
+ import SwitchCtrl from '../FormerControllers/SwitchCtrl.svelte';
11
+
12
+ interface UserForm {
13
+ id?: number;
14
+ firstName: string;
15
+ lastName: string;
16
+ email: string;
17
+ password: string;
18
+ age?: number;
19
+ role: string;
20
+ department: string;
21
+ bio: string;
22
+ website: string;
23
+ emailNotifications: boolean;
24
+ active: boolean;
25
+ }
26
+
27
+ interface Props {
28
+ request?: FormRequestType;
29
+ }
30
+
31
+ const { request = 'insert' }: Props = $props();
32
+
33
+ const emptyUser: UserForm = {
34
+ firstName: '',
35
+ lastName: '',
36
+ email: '',
37
+ password: '',
38
+ age: undefined,
39
+ role: '',
40
+ department: '',
41
+ bio: '',
42
+ website: '',
43
+ emailNotifications: true,
44
+ active: true,
45
+ };
46
+
47
+ const filledUser: UserForm = {
48
+ id: 1,
49
+ firstName: 'Jane',
50
+ lastName: 'Smith',
51
+ email: 'jane.smith@example.com',
52
+ password: '',
53
+ age: 32,
54
+ role: 'admin',
55
+ department: 'engineering',
56
+ bio: 'Senior software engineer with 10 years of experience building scalable systems.',
57
+ website: 'https://janesmith.dev',
58
+ emailNotifications: true,
59
+ active: true,
60
+ };
61
+
62
+ const roleOptions = [
63
+ { label: 'Admin', value: 'admin' },
64
+ { label: 'Editor', value: 'editor' },
65
+ { label: 'Viewer', value: 'viewer' },
66
+ ];
67
+
68
+ const departmentOptions = [
69
+ { label: 'Engineering', value: 'engineering' },
70
+ { label: 'Product', value: 'product' },
71
+ { label: 'Design', value: 'design' },
72
+ { label: 'Marketing', value: 'marketing' },
73
+ { label: 'Operations', value: 'operations' },
74
+ ];
75
+
76
+ let values = $state<UserForm>(request === 'insert' ? { ...emptyUser } : { ...filledUser });
77
+ let lastSaved = $state<UserForm | undefined>(undefined);
78
+ let opened = $state(false);
79
+ </script>
80
+
81
+ <div class="p-8 space-y-6">
82
+ <div class="space-y-2">
83
+ <button class="btn preset-filled-primary-token" onclick={() => (opened = true)}>
84
+ Open Drawer
85
+ </button>
86
+ {#if lastSaved}
87
+ <div class="card p-4">
88
+ <p class="font-semibold text-sm mb-2">Saved data:</p>
89
+ <pre class="text-xs overflow-auto">{JSON.stringify(lastSaved, null, 2)}</pre>
90
+ </div>
91
+ {/if}
92
+ </div>
93
+
94
+ <FormerDrawer
95
+ bind:values
96
+ bind:opened
97
+ {request}
98
+ onAPICall={async (mode, _req, data) => {
99
+ await new Promise((resolve) => setTimeout(resolve, 800));
100
+ if (mode === 'mutate') {
101
+ return { ...data, id: (data as UserForm)?.id ?? 42 } as UserForm;
102
+ }
103
+ return data as UserForm;
104
+ }}
105
+ afterSave={(data) => {
106
+ lastSaved = data as UserForm;
107
+ }}
108
+ onClose={() => {
109
+ opened = false;
110
+ }}
111
+ >
112
+ {#snippet children(state)}
113
+ {@const isReadonly = state.request === 'view' || state.request === 'delete'}
114
+
115
+ <div class="p-6 space-y-4">
116
+ <div class="grid grid-cols-2 gap-4">
117
+ <TextInputCtrl
118
+ label="First Name"
119
+ name="firstName"
120
+ value={state.values?.firstName ?? ''}
121
+ required
122
+ disabled={isReadonly}
123
+ onchange={(v) => state.setState('values', { ...state.values, firstName: v })}
124
+ />
125
+ <TextInputCtrl
126
+ label="Last Name"
127
+ name="lastName"
128
+ value={state.values?.lastName ?? ''}
129
+ required
130
+ disabled={isReadonly}
131
+ onchange={(v) => state.setState('values', { ...state.values, lastName: v })}
132
+ />
133
+ </div>
134
+
135
+ <TextInputCtrl
136
+ label="Email"
137
+ name="email"
138
+ type="email"
139
+ value={state.values?.email ?? ''}
140
+ required
141
+ disabled={isReadonly}
142
+ onchange={(v) => state.setState('values', { ...state.values, email: v })}
143
+ />
144
+
145
+ {#if state.request === 'insert'}
146
+ <PasswordInputCtrl
147
+ label="Password"
148
+ name="password"
149
+ value={state.values?.password ?? ''}
150
+ required
151
+ onchange={(v) => state.setState('values', { ...state.values, password: v })}
152
+ />
153
+ {/if}
154
+
155
+ <div class="grid grid-cols-2 gap-4">
156
+ <NumberInputCtrl
157
+ label="Age"
158
+ name="age"
159
+ value={state.values?.age}
160
+ min={18}
161
+ max={120}
162
+ disabled={isReadonly}
163
+ onchange={(v) => state.setState('values', { ...state.values, age: v })}
164
+ />
165
+ <TextInputCtrl
166
+ label="Website"
167
+ name="website"
168
+ type="url"
169
+ value={state.values?.website ?? ''}
170
+ disabled={isReadonly}
171
+ onchange={(v) => state.setState('values', { ...state.values, website: v })}
172
+ />
173
+ </div>
174
+
175
+ <div class="grid grid-cols-2 gap-4">
176
+ <NativeSelectCtrl
177
+ label="Role"
178
+ name="role"
179
+ value={state.values?.role ?? ''}
180
+ required
181
+ placeholder="Select role"
182
+ options={roleOptions}
183
+ disabled={isReadonly}
184
+ onchange={(v) => state.setState('values', { ...state.values, role: v })}
185
+ />
186
+ <NativeSelectCtrl
187
+ label="Department"
188
+ name="department"
189
+ value={state.values?.department ?? ''}
190
+ placeholder="Select department"
191
+ options={departmentOptions}
192
+ disabled={isReadonly}
193
+ onchange={(v) => state.setState('values', { ...state.values, department: v })}
194
+ />
195
+ </div>
196
+
197
+ <TextAreaCtrl
198
+ label="Bio"
199
+ name="bio"
200
+ value={state.values?.bio ?? ''}
201
+ rows={3}
202
+ placeholder="Tell us about yourself..."
203
+ disabled={isReadonly}
204
+ onchange={(v) => state.setState('values', { ...state.values, bio: v })}
205
+ />
206
+
207
+ <div class="flex gap-8">
208
+ <SwitchCtrl
209
+ label="Email Notifications"
210
+ name="emailNotifications"
211
+ checked={state.values?.emailNotifications ?? true}
212
+ disabled={isReadonly}
213
+ onchange={(c) => state.setState('values', { ...state.values, emailNotifications: c })}
214
+ />
215
+ <SwitchCtrl
216
+ label="Active"
217
+ name="active"
218
+ checked={state.values?.active ?? true}
219
+ disabled={isReadonly}
220
+ onchange={(c) => state.setState('values', { ...state.values, active: c })}
221
+ />
222
+ </div>
223
+ </div>
224
+ {/snippet}
225
+ </FormerDrawer>
226
+ </div>
@@ -0,0 +1,7 @@
1
+ import type { FormRequestType } from './types';
2
+ interface Props {
3
+ request?: FormRequestType;
4
+ }
5
+ declare const FormerDrawerPreview: import("svelte").Component<Props, {}, "">;
6
+ type FormerDrawerPreview = ReturnType<typeof FormerDrawerPreview>;
7
+ export default FormerDrawerPreview;
@@ -0,0 +1,108 @@
1
+ <script lang="ts">
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
3
+ import { Dialog, Portal } from '@skeletonlabs/skeleton-svelte';
4
+ import Former from './Former.svelte';
5
+ import type { FormerProps, FormRequestType } from './types';
6
+
7
+ interface Props extends FormerProps {
8
+ /**
9
+ * Override the auto-generated dialog title.
10
+ * When omitted the title is derived from the request type and the unique key value:
11
+ * insert → "New Record"
12
+ * update → "Edit Record — {key}"
13
+ * delete → "Delete Record — {key}"
14
+ */
15
+ title?: string;
16
+ }
17
+
18
+ let {
19
+ afterGet,
20
+ afterSave,
21
+ beforeSave,
22
+ children,
23
+ id,
24
+ keepOpen = $bindable(false),
25
+ layout,
26
+ onAPICall,
27
+ onChange,
28
+ onClose,
29
+ onConfirmDelete,
30
+ onError,
31
+ onOpen,
32
+ opened = $bindable(false),
33
+ primeData,
34
+ request = $bindable<FormRequestType>('insert'),
35
+ title,
36
+ uniqueKeyField = 'id',
37
+ values = $bindable<any>(undefined),
38
+ }: Props = $props();
39
+
40
+ const autoTitle = $derived(
41
+ title ??
42
+ (request === 'delete'
43
+ ? `Delete Record${(values as any)?.[uniqueKeyField] ? ` — ${(values as any)[uniqueKeyField]}` : ''}`
44
+ : request === 'insert'
45
+ ? 'New Record'
46
+ : `Edit Record${(values as any)?.[uniqueKeyField] ? ` — ${(values as any)[uniqueKeyField]}` : ''}`)
47
+ );
48
+
49
+ const animBackdrop =
50
+ 'transition transition-discrete opacity-0 starting:data-[state=open]:opacity-0 data-[state=open]:opacity-100';
51
+ const animContent =
52
+ 'transition transition-discrete opacity-0 scale-95 starting:data-[state=open]:opacity-0 starting:data-[state=open]:scale-95 data-[state=open]:opacity-100 data-[state=open]:scale-100';
53
+ </script>
54
+
55
+ <Dialog
56
+ open={opened}
57
+ onOpenChange={(e) => {
58
+ opened = e.open;
59
+ if (!e.open) onClose?.();
60
+ }}
61
+ closeOnInteractOutside={false}
62
+ closeOnEscape={false}
63
+ modal
64
+ >
65
+ <Portal>
66
+ <Dialog.Backdrop class="fixed inset-0 z-40 bg-black/50 backdrop-blur-sm {animBackdrop}" />
67
+ <Dialog.Positioner class="fixed inset-0 z-50 flex items-center justify-center p-4">
68
+ <Dialog.Content
69
+ class="card bg-surface-100-900 shadow-2xl w-full max-w-2xl max-h-[90vh] flex flex-col overflow-hidden {animContent}"
70
+ >
71
+ <header
72
+ class="flex items-center justify-between px-6 pt-5 pb-4 border-b border-surface-300-600 shrink-0"
73
+ >
74
+ <Dialog.Title class="text-lg font-semibold">{autoTitle}</Dialog.Title>
75
+ <Dialog.CloseTrigger class="btn-icon btn-icon-sm preset-tonal" aria-label="Close dialog">
76
+
77
+ </Dialog.CloseTrigger>
78
+ </header>
79
+
80
+ <div class="flex-1 min-h-0 overflow-auto">
81
+ <Former
82
+ bind:values
83
+ bind:opened
84
+ bind:request
85
+ bind:keepOpen
86
+ {afterGet}
87
+ {afterSave}
88
+ {beforeSave}
89
+ {children}
90
+ {id}
91
+ layout={{ buttonArea: 'bottom', ...layout }}
92
+ {onAPICall}
93
+ {onChange}
94
+ {onConfirmDelete}
95
+ {onError}
96
+ {onOpen}
97
+ {primeData}
98
+ {uniqueKeyField}
99
+ onClose={(data) => {
100
+ opened = false;
101
+ onClose?.(data);
102
+ }}
103
+ />
104
+ </div>
105
+ </Dialog.Content>
106
+ </Dialog.Positioner>
107
+ </Portal>
108
+ </Dialog>
@@ -0,0 +1,14 @@
1
+ import type { FormerProps } from './types';
2
+ interface Props extends FormerProps {
3
+ /**
4
+ * Override the auto-generated dialog title.
5
+ * When omitted the title is derived from the request type and the unique key value:
6
+ * insert → "New Record"
7
+ * update → "Edit Record — {key}"
8
+ * delete → "Delete Record — {key}"
9
+ */
10
+ title?: string;
11
+ }
12
+ declare const FormerModal: import("svelte").Component<Props, {}, "values" | "opened" | "request" | "keepOpen">;
13
+ type FormerModal = ReturnType<typeof FormerModal>;
14
+ export default FormerModal;