@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.
- package/LICENSE +73 -0
- package/README.md +3 -0
- package/dist/actions/index.d.ts +1 -0
- package/dist/actions/index.js +2 -0
- package/dist/components/BetterMenu/BetterMenu.stories.js +68 -0
- package/dist/components/BetterMenu/BetterMenu.svelte +38 -0
- package/dist/components/BetterMenu/BetterMenu.svelte.d.ts +14 -0
- package/dist/components/BetterMenu/BetterMenuAsyncButton.svelte +34 -0
- package/dist/components/BetterMenu/BetterMenuAsyncButton.svelte.d.ts +8 -0
- package/dist/components/BetterMenu/BetterMenuPreview.svelte +43 -0
- package/dist/components/BetterMenu/BetterMenuPreview.svelte.d.ts +7 -0
- package/dist/components/BetterMenu/MenuRenderer.svelte +75 -0
- package/dist/components/BetterMenu/MenuRenderer.svelte.d.ts +6 -0
- package/dist/components/BetterMenu/Plan.mdx +155 -0
- package/dist/components/BetterMenu/index.d.ts +4 -0
- package/dist/components/BetterMenu/index.js +4 -0
- package/dist/components/BetterMenu/store.d.ts +10 -0
- package/dist/components/BetterMenu/store.js +48 -0
- package/dist/components/BetterMenu/types.d.ts +24 -0
- package/dist/components/BetterMenu/types.js +1 -0
- package/dist/components/Boxer/Boxer.stories.d.ts +19 -0
- package/dist/components/Boxer/Boxer.stories.js +102 -0
- package/dist/components/Boxer/Boxer.svelte +411 -0
- package/dist/components/Boxer/Boxer.svelte.d.ts +11 -0
- package/dist/components/Boxer/BoxerTarget.svelte +88 -0
- package/dist/components/Boxer/BoxerTarget.svelte.d.ts +20 -0
- package/dist/components/Boxer/Plan.mdx +140 -0
- package/dist/components/Boxer/features.mdx +81 -0
- package/dist/components/Boxer/index.d.ts +4 -0
- package/dist/components/Boxer/index.js +4 -0
- package/dist/components/Boxer/store.d.ts +26 -0
- package/dist/components/Boxer/store.js +103 -0
- package/dist/components/Boxer/types.d.ts +46 -0
- package/dist/components/Boxer/types.js +1 -0
- package/dist/components/Button.stories.d.ts +11 -0
- package/dist/components/Button.stories.js +109 -0
- package/dist/components/Button.svelte +50 -0
- package/dist/components/Button.svelte.d.ts +12 -0
- package/dist/components/ButtonPreview.svelte +14 -0
- package/dist/components/ButtonPreview.svelte.d.ts +4 -0
- package/dist/components/ErrorBoundary/ErrorBoundary.stories.js +17 -0
- package/dist/components/ErrorBoundary/ErrorBoundary.svelte +127 -0
- package/dist/components/ErrorBoundary/ErrorBoundary.svelte.d.ts +13 -0
- package/dist/components/ErrorBoundary/ErrorBoundaryPreview.svelte +28 -0
- package/dist/components/ErrorBoundary/ErrorBoundaryPreview.svelte.d.ts +6 -0
- package/dist/components/ErrorBoundary/ErrorManager.d.ts +15 -0
- package/dist/components/ErrorBoundary/ErrorManager.js +158 -0
- package/dist/components/ErrorBoundary/Plan.mdx +182 -0
- package/dist/components/ErrorBoundary/index.d.ts +3 -0
- package/dist/components/ErrorBoundary/index.js +3 -0
- package/dist/components/ErrorBoundary/types.d.ts +43 -0
- package/dist/components/ErrorBoundary/types.js +1 -0
- package/dist/components/Former/Former.stories.js +228 -0
- package/dist/components/Former/Former.svelte +405 -0
- package/dist/components/Former/Former.svelte.d.ts +33 -0
- package/dist/components/Former/FormerButtonArea.svelte +93 -0
- package/dist/components/Former/FormerButtonArea.svelte.d.ts +15 -0
- package/dist/components/Former/FormerDrawer.svelte +115 -0
- package/dist/components/Former/FormerDrawer.svelte.d.ts +19 -0
- package/dist/components/Former/FormerDrawerPreview.svelte +226 -0
- package/dist/components/Former/FormerDrawerPreview.svelte.d.ts +7 -0
- package/dist/components/Former/FormerModal.svelte +108 -0
- package/dist/components/Former/FormerModal.svelte.d.ts +14 -0
- package/dist/components/Former/FormerModalPreview.svelte +226 -0
- package/dist/components/Former/FormerModalPreview.svelte.d.ts +7 -0
- package/dist/components/Former/FormerPreview.svelte +238 -0
- package/dist/components/Former/FormerPreview.svelte.d.ts +8 -0
- package/dist/components/Former/FormerResolveSpecAPI.d.ts +26 -0
- package/dist/components/Former/FormerResolveSpecAPI.js +44 -0
- package/dist/components/Former/FormerRestApiPreview.svelte +198 -0
- package/dist/components/Former/FormerRestApiPreview.svelte.d.ts +3 -0
- package/dist/components/Former/FormerRestHeadSpecAPI.d.ts +8 -0
- package/dist/components/Former/FormerRestHeadSpecAPI.js +38 -0
- package/dist/components/Former/Plan.mdx +115 -0
- package/dist/components/Former/formerState.svelte.d.ts +21 -0
- package/dist/components/Former/formerState.svelte.js +57 -0
- package/dist/components/Former/index.d.ts +8 -0
- package/dist/components/Former/index.js +8 -0
- package/dist/components/Former/types.d.ts +61 -0
- package/dist/components/Former/types.js +1 -0
- package/dist/components/FormerControllers/ButtonCtrl.stories.js +102 -0
- package/dist/components/FormerControllers/ButtonCtrl.svelte +65 -0
- package/dist/components/FormerControllers/ButtonCtrl.svelte.d.ts +14 -0
- package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrl.stories.js +73 -0
- package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrl.svelte +630 -0
- package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrl.svelte.d.ts +54 -0
- package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrl.utils.d.ts +40 -0
- package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrl.utils.js +688 -0
- package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrlCalendar.svelte +193 -0
- package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrlCalendar.svelte.d.ts +13 -0
- package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrlPickerPanel.svelte +119 -0
- package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrlPickerPanel.svelte.d.ts +39 -0
- package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrlTimeFields.svelte +343 -0
- package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrlTimeFields.svelte.d.ts +27 -0
- package/dist/components/FormerControllers/DateTimeCtrl/index.d.ts +2 -0
- package/dist/components/FormerControllers/DateTimeCtrl/index.js +1 -0
- package/dist/components/FormerControllers/FormerControllers.stories.js +76 -0
- package/dist/components/FormerControllers/IconButtonCtrl.stories.js +77 -0
- package/dist/components/FormerControllers/IconButtonCtrl.svelte +64 -0
- package/dist/components/FormerControllers/IconButtonCtrl.svelte.d.ts +13 -0
- package/dist/components/FormerControllers/InlineWrapper.stories.js +133 -0
- package/dist/components/FormerControllers/InlineWrapper.svelte +85 -0
- package/dist/components/FormerControllers/InlineWrapper.svelte.d.ts +16 -0
- package/dist/components/FormerControllers/InlineWrapperPreview.svelte +41 -0
- package/dist/components/FormerControllers/InlineWrapperPreview.svelte.d.ts +13 -0
- package/dist/components/FormerControllers/NativeSelectCtrl.stories.js +79 -0
- package/dist/components/FormerControllers/NativeSelectCtrl.svelte +61 -0
- package/dist/components/FormerControllers/NativeSelectCtrl.svelte.d.ts +13 -0
- package/dist/components/FormerControllers/NumberInputCtrl.stories.js +77 -0
- package/dist/components/FormerControllers/NumberInputCtrl.svelte +61 -0
- package/dist/components/FormerControllers/NumberInputCtrl.svelte.d.ts +11 -0
- package/dist/components/FormerControllers/PasswordInputCtrl.stories.js +79 -0
- package/dist/components/FormerControllers/PasswordInputCtrl.svelte +57 -0
- package/dist/components/FormerControllers/PasswordInputCtrl.svelte.d.ts +8 -0
- package/dist/components/FormerControllers/Plan.mdx +129 -0
- package/dist/components/FormerControllers/SwitchCtrl.stories.js +73 -0
- package/dist/components/FormerControllers/SwitchCtrl.svelte +38 -0
- package/dist/components/FormerControllers/SwitchCtrl.svelte.d.ts +8 -0
- package/dist/components/FormerControllers/TextAreaCtrl.stories.js +71 -0
- package/dist/components/FormerControllers/TextAreaCtrl.svelte +47 -0
- package/dist/components/FormerControllers/TextAreaCtrl.svelte.d.ts +9 -0
- package/dist/components/FormerControllers/TextInputCtrl.svelte +47 -0
- package/dist/components/FormerControllers/TextInputCtrl.svelte.d.ts +9 -0
- package/dist/components/FormerControllers/index.d.ts +12 -0
- package/dist/components/FormerControllers/index.js +11 -0
- package/dist/components/FormerControllers/types.d.ts +10 -0
- package/dist/components/FormerControllers/types.js +1 -0
- package/dist/components/GlobalStateStore/GlobalStateStore.d.ts +19 -0
- package/dist/components/GlobalStateStore/GlobalStateStore.js +349 -0
- package/dist/components/GlobalStateStore/GlobalStateStore.types.d.ts +127 -0
- package/dist/components/GlobalStateStore/GlobalStateStore.types.js +2 -0
- package/dist/components/GlobalStateStore/GlobalStateStore.utils.d.ts +4 -0
- package/dist/components/GlobalStateStore/GlobalStateStore.utils.js +92 -0
- package/dist/components/GlobalStateStore/GlobalStateStoreContext.d.ts +10 -0
- package/dist/components/GlobalStateStore/GlobalStateStoreContext.js +10 -0
- package/dist/components/GlobalStateStore/GlobalStateStoreProvider.svelte +113 -0
- package/dist/components/GlobalStateStore/GlobalStateStoreProvider.svelte.d.ts +16 -0
- package/dist/components/GlobalStateStore/index.d.ts +5 -0
- package/dist/components/GlobalStateStore/index.js +3 -0
- package/dist/components/Gridler/CellEditor.svelte +126 -0
- package/dist/components/Gridler/CellEditor.svelte.d.ts +15 -0
- package/dist/components/Gridler/Gridler.stories.d.ts +56 -0
- package/dist/components/Gridler/Gridler.stories.js +262 -0
- package/dist/components/Gridler/Gridler.svelte +778 -0
- package/dist/components/Gridler/Gridler.svelte.d.ts +11 -0
- package/dist/components/Gridler/GridlerHeader.svelte +179 -0
- package/dist/components/Gridler/GridlerHeader.svelte.d.ts +13 -0
- package/dist/components/Gridler/Plan.mdx +692 -0
- package/dist/components/Gridler/index.d.ts +6 -0
- package/dist/components/Gridler/index.js +6 -0
- package/dist/components/Gridler/types.d.ts +84 -0
- package/dist/components/Gridler/types.js +16 -0
- package/dist/components/Gridler/utils/rendering.d.ts +16 -0
- package/dist/components/Gridler/utils/rendering.js +202 -0
- package/dist/components/Gridler/utils/scrolling.d.ts +12 -0
- package/dist/components/Gridler/utils/scrolling.js +97 -0
- package/dist/components/Portal/Portal.mdx +125 -0
- package/dist/components/Portal/Portal.svelte +47 -0
- package/dist/components/Portal/Portal.svelte.d.ts +18 -0
- package/dist/components/Screenshot/Screenshot.stories.d.ts +16 -0
- package/dist/components/Screenshot/Screenshot.stories.js +15 -0
- package/dist/components/Screenshot/Screenshot.svelte +54 -0
- package/dist/components/Screenshot/Screenshot.svelte.d.ts +3 -0
- package/dist/components/Screenshot/Screenshot.util.d.ts +1 -0
- package/dist/components/Screenshot/Screenshot.util.js +49 -0
- package/dist/components/Screenshot/index.d.ts +2 -0
- package/dist/components/Screenshot/index.js +2 -0
- package/dist/components/Svark/Svark.stories.js +659 -0
- package/dist/components/Svark/Svark.svelte +691 -0
- package/dist/components/Svark/Svark.svelte.d.ts +26 -0
- package/dist/components/Svark/SvarkResolveSpecAdapter.d.ts +16 -0
- package/dist/components/Svark/SvarkResolveSpecAdapter.js +68 -0
- package/dist/components/Svark/SvarkSelectionDemo.svelte +59 -0
- package/dist/components/Svark/SvarkSelectionDemo.svelte.d.ts +4 -0
- package/dist/components/Svark/index.d.ts +3 -0
- package/dist/components/Svark/index.js +3 -0
- package/dist/components/Svark/types.d.ts +63 -0
- package/dist/components/Svark/types.js +1 -0
- package/dist/components/VTree/VTree.models.d.ts +12 -0
- package/dist/components/VTree/VTree.models.js +1 -0
- package/dist/components/VTree/VTree.stories.d.ts +40 -0
- package/dist/components/VTree/VTree.stories.js +112 -0
- package/dist/components/VTree/VTree.svelte +471 -0
- package/dist/components/VTree/VTree.svelte.d.ts +5 -0
- package/dist/components/VTree/VTreeContextMenu.svelte +40 -0
- package/dist/components/VTree/VTreeContextMenu.svelte.d.ts +11 -0
- package/dist/components/VTree/VTreeEventsDemo.svelte +88 -0
- package/dist/components/VTree/VTreeEventsDemo.svelte.d.ts +3 -0
- package/dist/components/VTree/VTreeResolveSpecAdapter.d.ts +14 -0
- package/dist/components/VTree/VTreeResolveSpecAdapter.js +103 -0
- package/dist/components/VTree/VTreeRow.svelte +136 -0
- package/dist/components/VTree/VTreeRow.svelte.d.ts +37 -0
- package/dist/components/VTree/VTreeSearch.svelte +25 -0
- package/dist/components/VTree/VTreeSearch.svelte.d.ts +8 -0
- package/dist/components/VTree/VTreeVirtualViewport.svelte +154 -0
- package/dist/components/VTree/VTreeVirtualViewport.svelte.d.ts +45 -0
- package/dist/components/VTree/index.d.ts +3 -0
- package/dist/components/VTree/index.js +3 -0
- package/dist/components/VTree/types.d.ts +83 -0
- package/dist/components/VTree/types.js +1 -0
- package/dist/components/index.d.ts +11 -0
- package/dist/components/index.js +11 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +20 -0
- package/dist/stores/index.d.ts +1 -0
- package/dist/stores/index.js +1 -0
- package/dist/themes/svelix_orange.css +205 -0
- package/dist/utils/PropsWithChildren.d.ts +5 -0
- package/dist/utils/PropsWithChildren.js +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +2 -0
- 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;
|