@blocklet/pages-kit-block-studio 0.6.51 → 0.6.53

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.
@@ -20,6 +20,9 @@ import { parsePropertyValue } from '@blocklet/pages-kit/utils/property';
20
20
  // @ts-ignore
21
21
  import { Dashboard } from '@blocklet/studio-ui';
22
22
  import { BlockletStudio } from '@blocklet/ui-react';
23
+ import { DndContext, DragOverlay, closestCorners, KeyboardSensor, PointerSensor, useSensor, useSensors, } from '@dnd-kit/core';
24
+ import { SortableContext, useSortable, verticalListSortingStrategy } from '@dnd-kit/sortable';
25
+ import { CSS } from '@dnd-kit/utilities';
23
26
  import AddIcon from '@mui/icons-material/Add';
24
27
  import DeleteIcon from '@mui/icons-material/Delete';
25
28
  import DragIndicatorIcon from '@mui/icons-material/DragIndicator';
@@ -34,9 +37,6 @@ import cloneDeep from 'lodash/cloneDeep';
34
37
  import get from 'lodash/get';
35
38
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
36
39
  import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
37
- import { DndProvider } from 'react-dnd';
38
- import { useDrag, useDrop } from 'react-dnd';
39
- import { HTML5Backend } from 'react-dnd-html5-backend';
40
40
  import { useLocation, useNavigate } from 'react-router-dom';
41
41
  import SplitPane, { Pane } from 'split-pane-react';
42
42
  import 'split-pane-react/esm/themes/default.css';
@@ -67,85 +67,21 @@ function useSessionContext() {
67
67
  const LEFT_DRAWER_WIDTH = 300;
68
68
  const RIGHT_DRAWER_WIDTH = 300;
69
69
  const defaultLocale = 'en';
70
- // Drag and drop types
71
- const ItemTypes = {
72
- ROUTE_ITEM: 'route-item',
73
- };
74
- const DraggableRouteItem = ({ route, staticDataInRoute, currentPageId, onNavigate, onDelete, index, moveItem, showDragHandle, routes, }) => {
75
- const ref = React.useRef(null);
70
+ const SortableRouteItem = ({ route, staticDataInRoute, currentPageId, onNavigate, onDelete, showDragHandle, isDragging = false, }) => {
76
71
  const [isHovered, setIsHovered] = React.useState(false);
77
- const [{ handlerId }, drop] = useDrop({
78
- accept: ItemTypes.ROUTE_ITEM,
79
- collect(monitor) {
80
- return {
81
- handlerId: monitor.getHandlerId(),
82
- };
83
- },
84
- hover(item, monitor) {
85
- if (!ref.current || !showDragHandle) {
86
- return;
87
- }
88
- // Get the real dragIndex from routes array using route as identifier
89
- // This prevents issues when dragging too fast and item.index becomes stale
90
- const dragIndex = routes.findIndex((r) => r === item.route);
91
- const hoverIndex = index;
92
- // Don't replace items with themselves
93
- if (dragIndex === hoverIndex || dragIndex === -1) {
94
- return;
95
- }
96
- // Determine rectangle on screen
97
- const hoverBoundingRect = ref.current?.getBoundingClientRect();
98
- // Get vertical middle
99
- const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
100
- // Determine mouse position
101
- const clientOffset = monitor.getClientOffset();
102
- // Get pixels to the top
103
- const hoverClientY = (clientOffset?.y ?? 0) - hoverBoundingRect.top;
104
- // Only perform the move when the mouse has crossed half of the items height
105
- // When dragging downwards, only move when the cursor is below 50%
106
- // When dragging upwards, only move when the cursor is above 50%
107
- // Dragging downwards
108
- if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
109
- return;
110
- }
111
- // Dragging upwards
112
- if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
113
- return;
114
- }
115
- // Time to actually perform the action
116
- moveItem(dragIndex, hoverIndex);
117
- // Note: we're mutating the monitor item here!
118
- // Generally it's better to avoid mutations,
119
- // but it's good here for the sake of performance
120
- // to avoid expensive index searches.
121
- item.index = hoverIndex;
122
- },
123
- });
124
- const [{ isDragging }, drag, preview] = useDrag({
125
- type: ItemTypes.ROUTE_ITEM,
126
- item: () => {
127
- return { route, index };
128
- },
129
- collect: (monitor) => ({
130
- isDragging: monitor.isDragging(),
131
- }),
132
- canDrag: showDragHandle,
72
+ const { attributes, listeners, setNodeRef, transform, transition } = useSortable({
73
+ id: route,
74
+ disabled: !showDragHandle,
133
75
  });
134
- const opacity = isDragging ? 0.5 : 1;
135
- // Separate drag handle from the clickable area
136
- const dragHandleRef = React.useRef(null);
137
- // Only attach drag to the handle when in custom sort mode
138
- React.useEffect(() => {
139
- if (showDragHandle && dragHandleRef.current) {
140
- drag(dragHandleRef.current);
141
- }
142
- }, [drag, showDragHandle]);
143
- drop(ref);
144
- return (_jsx(ListItem, { ref: ref, disablePadding: true, className: isDragging ? 'drag-shaking' : '', sx: {
145
- opacity,
76
+ const style = {
77
+ transform: CSS.Transform.toString(transform),
78
+ transition,
79
+ opacity: isDragging ? 0.5 : 1,
80
+ };
81
+ return (_jsx(ListItem, { ref: setNodeRef, style: style, disablePadding: true, className: isDragging ? 'drag-shaking' : '', sx: {
146
82
  transition: isDragging ? 'opacity 0.2s ease' : 'opacity 0.2s ease, transform 0.2s ease',
147
83
  zIndex: isDragging ? 1000 : 'auto',
148
- }, "data-handler-id": handlerId, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: _jsxs(ListItemButton, { selected: currentPageId === route, onClick: () => onNavigate(route), sx: {
84
+ }, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: _jsxs(ListItemButton, { selected: currentPageId === route, onClick: () => onNavigate(route), sx: {
149
85
  borderRadius: 1,
150
86
  width: '100%',
151
87
  textOverflow: 'ellipsis',
@@ -167,7 +103,7 @@ const DraggableRouteItem = ({ route, staticDataInRoute, currentPageId, onNavigat
167
103
  backgroundColor: isDragging ? 'grey.100' : 'inherit',
168
104
  pl: 1,
169
105
  pr: 1,
170
- }, children: [showDragHandle && (_jsx(Box, { ref: dragHandleRef, sx: {
106
+ }, children: [showDragHandle && (_jsx(Box, { ...attributes, ...listeners, sx: {
171
107
  display: 'flex',
172
108
  alignItems: 'center',
173
109
  justifyContent: 'center',
@@ -267,6 +203,7 @@ function Layout({ loadState, loadedData }) {
267
203
  draggingSplitPane: false,
268
204
  simulatorType: 'pc',
269
205
  iframeLoaded: false,
206
+ dragOverlay: null,
270
207
  });
271
208
  const { theme, mode, changeMode } = useConfig();
272
209
  // 添加renderComponentTrigger状态,用于触发组件重新渲染
@@ -494,16 +431,35 @@ function Layout({ loadState, loadedData }) {
494
431
  height: '100%',
495
432
  }, children: _jsx(Skeleton, { variant: "rectangular", height: "100%", sx: { borderRadius: 1 } }) }));
496
433
  }, []);
497
- // Move item function for drag and drop
498
- const moveItem = useCallback((dragIndex, hoverIndex) => {
499
- if (dragIndex === hoverIndex)
434
+ // Configure sensors for dnd-kit
435
+ const sensors = useSensors(useSensor(PointerSensor, {
436
+ activationConstraint: {
437
+ distance: 8, // 8px movement required to start drag
438
+ },
439
+ }), useSensor(KeyboardSensor));
440
+ // Drag event handlers
441
+ const handleDragStart = (event) => {
442
+ const { active } = event;
443
+ state.dragOverlay = active.id;
444
+ };
445
+ const handleDragEnd = (event) => {
446
+ const { active, over } = event;
447
+ state.dragOverlay = null;
448
+ if (!over || active.id === over.id) {
500
449
  return;
501
- const newRoutes = [...routes];
502
- const [draggedItem] = newRoutes.splice(dragIndex, 1);
503
- newRoutes.splice(hoverIndex, 0, draggedItem);
504
- // Save the new order to localStorage (automatically enables custom sort)
505
- setCustomSortOrder(newRoutes);
506
- }, [routes, setCustomSortOrder]);
450
+ }
451
+ const activeRoute = active.id;
452
+ const overRoute = over.id;
453
+ const activeIndex = routes.findIndex((route) => route === activeRoute);
454
+ const overIndex = routes.findIndex((route) => route === overRoute);
455
+ if (activeIndex !== -1 && overIndex !== -1) {
456
+ const newRoutes = [...routes];
457
+ const [draggedItem] = newRoutes.splice(activeIndex, 1);
458
+ newRoutes.splice(overIndex, 0, draggedItem);
459
+ // Save the new order to localStorage (automatically enables custom sort)
460
+ setCustomSortOrder(newRoutes);
461
+ }
462
+ };
507
463
  // 修改 iframe URL 构建逻辑,添加初始状态参数
508
464
  const iframeUrl = useMemo(() => {
509
465
  const url = new URL(window.location.href);
@@ -600,30 +556,38 @@ function Layout({ loadState, loadedData }) {
600
556
  },
601
557
  }, children: _jsx(SortByAlphaIcon, { fontSize: "small" }) }) })), _jsx(Button, { variant: "contained", sx: { minWidth: 40 }, onClick: () => {
602
558
  state.createBlockOpen = true;
603
- }, children: _jsx(AddIcon, { fontSize: "small" }) })] }), routes?.length > 0 ? (_jsx(List, { sx: {
604
- pr: 1,
605
- overflowY: 'auto',
606
- height: hasCustomSort ? 'calc(100% - 80px)' : 'calc(100% - 60px)',
607
- // Prevent text selection during drag
608
- userSelect: 'none',
609
- }, children: routes
610
- .map((route, index) => {
611
- const routeName = route;
612
- const staticDataInRoute = staticData[route]?.main;
613
- if (state.searchValue && !routeName?.toLowerCase().includes(state.searchValue?.toLowerCase())) {
614
- return null;
615
- }
616
- if (!state.allComponents?.find(({ blockName }) => `/${blockName}` === routeName)) {
617
- return null;
618
- }
619
- return (_jsx(DraggableRouteItem, { route: route, staticDataInRoute: staticDataInRoute, currentPageId: currentPage.pageId, onNavigate: (route) => {
620
- if (route !== currentPage.pageId) {
621
- navigate(route);
622
- state.iframeLoaded = false;
623
- }
624
- }, onDelete: handleDeleteBlock, index: index, moveItem: moveItem, showDragHandle: true, routes: routes }, route));
625
- })
626
- .filter(Boolean) })) : (_jsx(Box, { sx: {
559
+ }, children: _jsx(AddIcon, { fontSize: "small" }) })] }), routes?.length > 0 ? (_jsxs(DndContext, { sensors: sensors, collisionDetection: closestCorners, onDragStart: handleDragStart, onDragEnd: handleDragEnd, children: [_jsx(SortableContext, { items: routes, strategy: verticalListSortingStrategy, children: _jsx(List, { sx: {
560
+ pr: 1,
561
+ overflowY: 'auto',
562
+ height: hasCustomSort ? 'calc(100% - 80px)' : 'calc(100% - 60px)',
563
+ // Prevent text selection during drag
564
+ userSelect: 'none',
565
+ }, children: routes
566
+ .map((route) => {
567
+ const routeName = route;
568
+ const staticDataInRoute = staticData[route]?.main;
569
+ if (state.searchValue && !routeName?.toLowerCase().includes(state.searchValue?.toLowerCase())) {
570
+ return null;
571
+ }
572
+ if (!state.allComponents?.find(({ blockName }) => `/${blockName}` === routeName)) {
573
+ return null;
574
+ }
575
+ return (_jsx(SortableRouteItem, { route: route, staticDataInRoute: staticDataInRoute, currentPageId: currentPage.pageId, onNavigate: (route) => {
576
+ if (route !== currentPage.pageId) {
577
+ navigate(route);
578
+ state.iframeLoaded = false;
579
+ }
580
+ }, onDelete: handleDeleteBlock, showDragHandle: true, isDragging: state.dragOverlay === route }, route));
581
+ })
582
+ .filter(Boolean) }) }), _jsx(DragOverlay, { children: state.dragOverlay ? (_jsx(Box, { sx: {
583
+ opacity: 0.8,
584
+ backgroundColor: 'background.paper',
585
+ border: '1px solid',
586
+ borderColor: 'primary.main',
587
+ borderRadius: 1,
588
+ boxShadow: 2,
589
+ maxWidth: 280,
590
+ }, children: _jsx(SortableRouteItem, { route: state.dragOverlay, staticDataInRoute: staticData[state.dragOverlay]?.main, currentPageId: currentPage.pageId, onNavigate: () => { }, onDelete: () => { }, showDragHandle: true, isDragging: true }) })) : null })] })) : (_jsx(Box, { sx: {
627
591
  display: 'flex',
628
592
  justifyContent: 'center',
629
593
  alignItems: 'center',
@@ -652,8 +616,11 @@ function Layout({ loadState, loadedData }) {
652
616
  state.allComponents,
653
617
  state.searchValue,
654
618
  state.draggingSplitPane,
619
+ state.dragOverlay,
655
620
  hasCustomSort,
656
- moveItem,
621
+ sensors,
622
+ handleDragStart,
623
+ handleDragEnd,
657
624
  currentPage.pageId,
658
625
  navigate,
659
626
  locale,
@@ -1036,72 +1003,70 @@ function Layout({ loadState, loadedData }) {
1036
1003
  if (isInsideIframe) {
1037
1004
  return middlePanelContent;
1038
1005
  }
1039
- return (_jsx(DndProvider, { backend: HTML5Backend, children: _jsxs(StyledDashboard, { HeaderProps: {
1040
- // @ts-ignore
1041
- homeLink: joinURL(basename),
1042
- addons: (addons) => {
1043
- return [
1044
- _jsx(Button, { onClick: async () => {
1045
- if (!session?.user?.did) {
1046
- Toast.warning(t('themeTranslations.connectWallet'));
1047
- await session.login();
1048
- setTimeout(() => {
1049
- state.createResourceOpen = true;
1050
- }, 1000);
1051
- }
1052
- else {
1006
+ return (_jsxs(StyledDashboard, { HeaderProps: {
1007
+ // @ts-ignore
1008
+ homeLink: joinURL(basename),
1009
+ addons: (addons) => {
1010
+ return [
1011
+ _jsx(Button, { onClick: async () => {
1012
+ if (!session?.user?.did) {
1013
+ Toast.warning(t('themeTranslations.connectWallet'));
1014
+ await session.login();
1015
+ setTimeout(() => {
1053
1016
  state.createResourceOpen = true;
1054
- }
1055
- }, children: t('themeTranslations.createResource') }, "logout"),
1056
- ...addons,
1057
- ];
1058
- },
1059
- }, MenusDrawerProps: { sx: { [`.${backdropClasses.root}`]: { top: 64 } } }, children: [_jsxs(StyledSplitPane, { split: "vertical", sizes: hSizes, onChange: setHSizes, sashRender: SashRender, onDragStart: () => (state.draggingSplitPane = true), onDragEnd: () => (state.draggingSplitPane = false), sx: {
1060
- '&.react-split--dragging': {
1061
- '.react-split__pane': {
1062
- '*': {
1063
- userSelect: 'none',
1064
- },
1017
+ }, 1000);
1018
+ }
1019
+ else {
1020
+ state.createResourceOpen = true;
1021
+ }
1022
+ }, children: t('themeTranslations.createResource') }, "logout"),
1023
+ ...addons,
1024
+ ];
1025
+ },
1026
+ }, MenusDrawerProps: { sx: { [`.${backdropClasses.root}`]: { top: 64 } } }, children: [_jsxs(StyledSplitPane, { split: "vertical", sizes: hSizes, onChange: setHSizes, sashRender: SashRender, onDragStart: () => (state.draggingSplitPane = true), onDragEnd: () => (state.draggingSplitPane = false), sx: {
1027
+ '&.react-split--dragging': {
1028
+ '.react-split__pane': {
1029
+ '*': {
1030
+ userSelect: 'none',
1065
1031
  },
1066
1032
  },
1067
- flex: 1,
1068
- }, children: [_jsx(Pane, { minSize: 100, maxSize: 400, children: leftPanelContent }), _jsx(Pane, { minSize: 400, children: middlePanelContent }), _jsx(Pane, { minSize: 100, maxSize: '30%', children: rightPanelContent })] }), _jsx(CreateResource, { open: state.createResourceOpen, onClose: () => {
1069
- state.createResourceOpen = false;
1070
- } }), _jsxs(Dialog, { open: state.createBlockOpen, onClose: onCloseCreateBlock, children: [_jsx(DialogTitle, { children: t('themeTranslations.createNewBlock') }), _jsx(DialogContent, { children: _jsxs(Stack, { spacing: 2, sx: { pt: 1, minWidth: 300 }, children: [_jsx(TextField, { autoFocus: true, required: true, label: t('themeTranslations.name'), fullWidth: true, value: state.newBlockParams.name, onChange: (e) => {
1071
- state.newBlockParams.name = e.target.value.replace(/[^a-zA-Z0-9-]/g, '');
1072
- } }), _jsx(TextField, { label: t('themeTranslations.description'), fullWidth: true, multiline: true, rows: 3, value: state.newBlockParams.description, onChange: (e) => {
1073
- state.newBlockParams.description = e.target.value;
1074
- } }), _jsx(Button, { variant: "contained", fullWidth: true, onClick: async () => {
1075
- if (!state.newBlockParams.name) {
1076
- Toast.warning(t('themeTranslations.blockNameRequired'));
1077
- return;
1078
- }
1079
- if (routes.some((route) => {
1080
- const staticDataInRoute = staticData[route]?.main;
1081
- return staticDataInRoute?.blockName?.toLowerCase() === state.newBlockParams.name.toLowerCase();
1082
- })) {
1083
- Toast.warning(t('themeTranslations.blockNameExists'));
1084
- return;
1085
- }
1086
- try {
1087
- await api.post('/api/blocks/create', state.newBlockParams);
1088
- state.init = false;
1089
- setTimeout(() => {
1090
- navigate(`/${state.newBlockParams.name}?no-redirect=true`);
1091
- onCloseCreateBlock();
1092
- }, 1000);
1093
- }
1094
- catch (error) {
1095
- console.error('Failed to create block:', error);
1096
- Toast.error(t('themeTranslations.failedCreateBlock'));
1097
- }
1098
- }, children: t('themeTranslations.create') })] }) })] }), _jsx(ComparisonPreviewDialog, { open: state.previewDialog.open, title: state.previewDialog.title, leftTitle: state.previewDialog.leftTitle, leftContent: state.previewDialog.leftContent, rightTitle: state.previewDialog.rightTitle, rightContent: state.previewDialog.rightContent, description: state.previewDialog.description, loading: state.previewDialog.loading, onConfirm: state.previewDialog.onConfirm, onClose: () => {
1099
- state.previewDialog.open = false;
1100
- } }), _jsxs(Dialog, { open: state.deleteConfirmDialog.open, onClose: () => (state.deleteConfirmDialog.open = false), maxWidth: "sm", fullWidth: true, children: [_jsx(DialogTitle, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: t('themeTranslations.deleteComponent') }), _jsxs(DialogContent, { children: [_jsx(Alert, { severity: "warning", sx: { mb: 2 }, children: t('themeTranslations.deleteWarning') }), _jsx(Typography, { children: t('themeTranslations.deleteConfirmMessage', {
1101
- componentName: state.deleteConfirmDialog.blockName,
1102
- }) })] }), _jsxs(Box, { sx: { display: 'flex', justifyContent: 'flex-end', p: 2, gap: 1 }, children: [_jsx(Button, { variant: "outlined", onClick: () => (state.deleteConfirmDialog.open = false), disabled: state.deleteConfirmDialog.loading, children: t('themeTranslations.cancel') }), _jsx(Button, { variant: "contained", color: "error", onClick: confirmDeleteBlock, disabled: state.deleteConfirmDialog.loading, startIcon: state.deleteConfirmDialog.loading ? _jsx(CircularProgress, { size: 20 }) : _jsx(DeleteIcon, {}), children: state.deleteConfirmDialog.loading
1103
- ? t('themeTranslations.deleting')
1104
- : t('themeTranslations.deleteConfirm') })] })] })] }) }));
1033
+ },
1034
+ flex: 1,
1035
+ }, children: [_jsx(Pane, { minSize: 100, maxSize: 400, children: leftPanelContent }), _jsx(Pane, { minSize: 400, children: middlePanelContent }), _jsx(Pane, { minSize: 100, maxSize: '30%', children: rightPanelContent })] }), _jsx(CreateResource, { open: state.createResourceOpen, onClose: () => {
1036
+ state.createResourceOpen = false;
1037
+ } }), _jsxs(Dialog, { open: state.createBlockOpen, onClose: onCloseCreateBlock, children: [_jsx(DialogTitle, { children: t('themeTranslations.createNewBlock') }), _jsx(DialogContent, { children: _jsxs(Stack, { spacing: 2, sx: { pt: 1, minWidth: 300 }, children: [_jsx(TextField, { autoFocus: true, required: true, label: t('themeTranslations.name'), fullWidth: true, value: state.newBlockParams.name, onChange: (e) => {
1038
+ state.newBlockParams.name = e.target.value.replace(/[^a-zA-Z0-9-]/g, '');
1039
+ } }), _jsx(TextField, { label: t('themeTranslations.description'), fullWidth: true, multiline: true, rows: 3, value: state.newBlockParams.description, onChange: (e) => {
1040
+ state.newBlockParams.description = e.target.value;
1041
+ } }), _jsx(Button, { variant: "contained", fullWidth: true, onClick: async () => {
1042
+ if (!state.newBlockParams.name) {
1043
+ Toast.warning(t('themeTranslations.blockNameRequired'));
1044
+ return;
1045
+ }
1046
+ if (routes.some((route) => {
1047
+ const staticDataInRoute = staticData[route]?.main;
1048
+ return staticDataInRoute?.blockName?.toLowerCase() === state.newBlockParams.name.toLowerCase();
1049
+ })) {
1050
+ Toast.warning(t('themeTranslations.blockNameExists'));
1051
+ return;
1052
+ }
1053
+ try {
1054
+ await api.post('/api/blocks/create', state.newBlockParams);
1055
+ state.init = false;
1056
+ setTimeout(() => {
1057
+ navigate(`/${state.newBlockParams.name}?no-redirect=true`);
1058
+ onCloseCreateBlock();
1059
+ }, 1000);
1060
+ }
1061
+ catch (error) {
1062
+ console.error('Failed to create block:', error);
1063
+ Toast.error(t('themeTranslations.failedCreateBlock'));
1064
+ }
1065
+ }, children: t('themeTranslations.create') })] }) })] }), _jsx(ComparisonPreviewDialog, { open: state.previewDialog.open, title: state.previewDialog.title, leftTitle: state.previewDialog.leftTitle, leftContent: state.previewDialog.leftContent, rightTitle: state.previewDialog.rightTitle, rightContent: state.previewDialog.rightContent, description: state.previewDialog.description, loading: state.previewDialog.loading, onConfirm: state.previewDialog.onConfirm, onClose: () => {
1066
+ state.previewDialog.open = false;
1067
+ } }), _jsxs(Dialog, { open: state.deleteConfirmDialog.open, onClose: () => (state.deleteConfirmDialog.open = false), maxWidth: "sm", fullWidth: true, children: [_jsx(DialogTitle, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: t('themeTranslations.deleteComponent') }), _jsxs(DialogContent, { children: [_jsx(Alert, { severity: "warning", sx: { mb: 2 }, children: t('themeTranslations.deleteWarning') }), _jsx(Typography, { children: t('themeTranslations.deleteConfirmMessage', {
1068
+ componentName: state.deleteConfirmDialog.blockName,
1069
+ }) })] }), _jsxs(Box, { sx: { display: 'flex', justifyContent: 'flex-end', p: 2, gap: 1 }, children: [_jsx(Button, { variant: "outlined", onClick: () => (state.deleteConfirmDialog.open = false), disabled: state.deleteConfirmDialog.loading, children: t('themeTranslations.cancel') }), _jsx(Button, { variant: "contained", color: "error", onClick: confirmDeleteBlock, disabled: state.deleteConfirmDialog.loading, startIcon: state.deleteConfirmDialog.loading ? _jsx(CircularProgress, { size: 20 }) : _jsx(DeleteIcon, {}), children: state.deleteConfirmDialog.loading ? t('themeTranslations.deleting') : t('themeTranslations.deleteConfirm') })] })] })] }));
1105
1070
  }
1106
1071
  // Add SplitPane styling
1107
1072
  const StyledSplitPane = styled(SplitPane) `