-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathDesignDrawer.tsx
More file actions
115 lines (108 loc) · 3.41 KB
/
Copy pathDesignDrawer.tsx
File metadata and controls
115 lines (108 loc) · 3.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/**
* DesignDrawer
*
* A right-side drawer that hosts visual editors (PageCanvasEditor / DashboardEditor)
* for inline editing with real-time preview. Uses the Shadcn Sheet primitive so the
* main workspace remains visible while the user edits.
*/
import { useCallback, useEffect, useRef } from 'react';
import {
Sheet,
SheetContent,
SheetHeader,
SheetTitle,
SheetDescription,
} from '@object-ui/components';
import { toast } from 'sonner';
import { useAdapter } from '../context/AdapterProvider';
export interface DesignDrawerProps {
/** Whether the drawer is open */
open: boolean;
/** Called when the drawer requests close */
onOpenChange: (open: boolean) => void;
/** Human-readable title shown in the drawer header */
title: string;
/** Optional description */
description?: string;
/** The current schema (PageSchema | DashboardSchema) */
schema: any;
/** Called when the editor modifies the schema — parent updates its own state for live preview */
onSchemaChange: (updated: any) => void;
/** sys_page | sys_dashboard */
collection: string;
/** Record key for the update call */
recordName: string;
/** Render prop: receives (schema, onChange) and returns the editor JSX */
children: (schema: any, onChange: (updated: any) => void) => React.ReactNode;
}
export function DesignDrawer({
open,
onOpenChange,
title,
description,
schema,
onSchemaChange,
collection,
recordName,
children,
}: DesignDrawerProps) {
const dataSource = useAdapter();
const schemaRef = useRef(schema);
schemaRef.current = schema;
const saveSchema = useCallback(
async (toSave: any) => {
try {
if (dataSource) {
await dataSource.update(collection, recordName, toSave);
return true;
}
} catch (err) {
console.warn('[DesignDrawer] Auto-save failed:', err);
// Save errors are non-blocking; user can retry via Ctrl+S
}
return false;
},
[dataSource, collection, recordName],
);
const handleChange = useCallback(
async (updated: any) => {
onSchemaChange(updated);
await saveSchema(updated);
},
[onSchemaChange, saveSchema],
);
// Ctrl+S / Cmd+S keyboard shortcut to explicitly save while drawer is open
useEffect(() => {
if (!open) return;
const handleKeyDown = (e: KeyboardEvent) => {
if ((e.ctrlKey || e.metaKey) && e.key === 's') {
e.preventDefault();
saveSchema(schemaRef.current).then((ok) => {
if (ok) toast.success(`${title} saved`);
});
}
};
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, [open, saveSchema, title]);
return (
<Sheet open={open} onOpenChange={onOpenChange} modal={false}>
<SheetContent
side="right"
hideOverlay
className="w-full sm:w-[540px] sm:max-w-[540px] lg:w-[640px] lg:max-w-[640px] p-0 flex flex-col"
data-testid="design-drawer"
>
<SheetHeader className="px-4 py-3 border-b shrink-0">
<SheetTitle>{title}</SheetTitle>
<SheetDescription className={description ? '' : 'sr-only'}>
{description || `Visual editor — configure and preview ${title}`}
</SheetDescription>
</SheetHeader>
<div className="flex-1 overflow-auto p-4">
{children(schema, handleChange)}
</div>
</SheetContent>
</Sheet>
);
}