playbook_ui 15.5.0.pre.alpha.draggablefix12571 → 15.5.0.pre.alpha.draggablefix12577

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1f31083e3e9ebfce2990300a17297cd86ed63b44c4396d2cea0802213fbf7820
4
- data.tar.gz: 5b0258ee4a8371746217cab20a86c325947c131d0085ef3e7ab9a406675bcd60
3
+ metadata.gz: 1dd11c97564a274020baa3c9a59aec465d0b9b67bcada5422063c88fd3a17adf
4
+ data.tar.gz: f302928fcde263a9d8a3d5611ff220066a3a64c00ce4a2679157c3d21a19b88c
5
5
  SHA512:
6
- metadata.gz: 963b09db6cf28ece7d25880e789d510046f7f283d4e73ec9b959dcaa9abb6040d489480a5e90776639bb202f04197cd7e5c8ded45a2ce793513a5a3dfca95bb8
7
- data.tar.gz: 567cacd6dcf108dacc6d6a1500d233ee8d3ce5d2c56ab6e0ddd131bca6d0c7d1dafe718ff7479eb0d99cd923db7708aafe1b32df2e9e16b3f6e6628cd44fcc00
6
+ metadata.gz: 3197dab744a56215624076b7d6a43a47263784e85ed51030d850386a2fd4948b3d824b80e258ddcf14d4ff34c82af5964c762fa42315d11ddc8bf8b61286a5c1
7
+ data.tar.gz: f6346ae11b7151409e7b52a1fe80b254ca8371bf2506caaa6febe4c539b220888a61bf90bd5c9dbe1e0318e36de437aedc8aeb7770fdfb3c0d698ba47e5a71d3
@@ -791,6 +791,28 @@
791
791
  box-shadow: 1px 0px 0px 0px var(--column-border-color) !important;
792
792
  }
793
793
 
794
+ // Override last-header-cell border color in dark mode
795
+ .pb_advanced_table_header {
796
+ > tr:not(:first-child) {
797
+ .last-header-cell {
798
+ border-right: 1px solid $border_dark !important;
799
+ }
800
+ }
801
+
802
+ th[colspan]:not([colspan="1"]) {
803
+ border-right: 1px solid $border_dark !important;
804
+ }
805
+ }
806
+
807
+ // Override last-cell border color in dark mode for body cells
808
+ .pb_advanced_table_body {
809
+ tr {
810
+ .last-cell:not(:last-of-type) {
811
+ border-right: 1px solid $border_dark !important;
812
+ }
813
+ }
814
+ }
815
+
794
816
  // Apply border colors in dark mode
795
817
  &[class*="column-group-border-"] {
796
818
  // For top-level column groups (ENROLLMENT DATA, PERFORMANCE DATA)
@@ -850,7 +872,7 @@
850
872
  // Restore vertical border styling in dark mode when verticalBorder is true
851
873
  .pb_table[data-vertical-border="true"] {
852
874
  .pb_advanced_table_header {
853
- > tr:not(:first-child) {
875
+ > tr {
854
876
  th:not(:last-child) {
855
877
  border-right: 1px solid $border_dark !important;
856
878
  }
@@ -864,11 +886,17 @@
864
886
  }
865
887
  }
866
888
 
889
+ tr.virtualized-table-row {
890
+ td:not(:last-child) {
891
+ border-right: 1px solid $border_dark !important;
892
+ }
893
+ }
894
+
867
895
  // When both verticalBorder AND columnGroupBorderColor are set in dark mode,
868
896
  // override the default border-dark with the custom color
869
897
  &.pb_advanced_table[class*="column-group-border-"] {
870
898
  .pb_advanced_table_header {
871
- > tr:not(:first-child) {
899
+ > tr {
872
900
  th:not(:last-child) {
873
901
  border-right: 1px solid var(--column-border-color) !important;
874
902
  }
@@ -881,6 +909,12 @@
881
909
  border-right: 1px solid var(--column-border-color) !important;
882
910
  }
883
911
  }
912
+
913
+ tr.virtualized-table-row {
914
+ td:not(:last-child) {
915
+ border-right: 1px solid var(--column-border-color) !important;
916
+ }
917
+ }
884
918
  }
885
919
  }
886
920
 
@@ -985,34 +1019,90 @@
985
1019
  // Firefox-specific fix for last-header-cell and last-cell vertical borders
986
1020
  @-moz-document url-prefix() {
987
1021
  .pb_advanced_table_header {
988
- .last-header-cell:not(:last-child) {
1022
+ th[colspan]:not([colspan="1"]):not(:last-child) {
1023
+ border-right: none !important;
1024
+ box-shadow: 1px 0 0 0 $border_light !important;
1025
+ }
1026
+
1027
+ .last-header-cell:not(:last-child),
1028
+ > tr:last-child .last-header-cell:not(:last-child) {
989
1029
  border-right: none !important;
990
1030
  box-shadow: 1px 0 0 0 $border_light !important;
991
1031
  }
992
1032
  }
993
1033
 
994
1034
  .pb_advanced_table_body {
995
- .last-cell:not(:last-child) {
1035
+ tr .last-cell:not(:last-of-type),
1036
+ td.last-cell:not(:last-child),
1037
+ .pb_table_td.last-cell:not(:last-child) {
996
1038
  border-right: none !important;
997
1039
  box-shadow: 1px 0 0 0 $border_light !important;
998
1040
  }
999
1041
  }
1000
1042
 
1043
+ &[class*="column-group-border-"] {
1044
+ .pb_advanced_table_header {
1045
+ th[colspan]:not([colspan="1"]):not(:last-child),
1046
+ .last-header-cell:not(:last-child),
1047
+ > tr:last-child .last-header-cell:not(:last-child) {
1048
+ box-shadow: 1px 0 0 0 var(--column-border-color) !important;
1049
+ }
1050
+ }
1051
+
1052
+ .pb_advanced_table_body {
1053
+ tr .last-cell:not(:last-of-type),
1054
+ td.last-cell:not(:last-child),
1055
+ .pb_table_td.last-cell:not(:last-child) {
1056
+ box-shadow: 1px 0 0 0 var(--column-border-color) !important;
1057
+ }
1058
+ }
1059
+ }
1060
+
1001
1061
  // Dark mode Firefox fixes
1002
1062
  &.dark {
1003
1063
  .pb_advanced_table_header {
1004
- .last-header-cell:not(:last-child) {
1064
+ // Convert all colspan headers to box-shadow with dark color
1065
+ th[colspan]:not([colspan="1"]) {
1066
+ border-right: none !important;
1067
+ box-shadow: 1px 0 0 0 $border_dark !important;
1068
+ }
1069
+
1070
+ // Convert all last-header-cell borders to box-shadow with dark color
1071
+ .last-header-cell:not(:last-child),
1072
+ > tr:last-child .last-header-cell:not(:last-child),
1073
+ > tr:not(:first-child) .last-header-cell:not(:last-child),
1074
+ > tr:not(:first-child) .last-header-cell:last-child {
1005
1075
  border-right: none !important;
1006
1076
  box-shadow: 1px 0 0 0 $border_dark !important;
1007
1077
  }
1008
1078
  }
1009
1079
 
1010
1080
  .pb_advanced_table_body {
1011
- .last-cell:not(:last-child) {
1081
+ tr .last-cell:not(:last-of-type),
1082
+ td.last-cell:not(:last-child),
1083
+ .pb_table_td.last-cell:not(:last-child) {
1012
1084
  border-right: none !important;
1013
1085
  box-shadow: 1px 0 0 0 $border_dark !important;
1014
1086
  }
1015
1087
  }
1088
+
1089
+ &[class*="column-group-border-"] {
1090
+ .pb_advanced_table_header {
1091
+ th[colspan]:not([colspan="1"]):not(:last-child),
1092
+ .last-header-cell:not(:last-child),
1093
+ > tr:last-child .last-header-cell:not(:last-child) {
1094
+ box-shadow: 1px 0 0 0 var(--column-border-color) !important;
1095
+ }
1096
+ }
1097
+
1098
+ .pb_advanced_table_body {
1099
+ tr .last-cell:not(:last-of-type),
1100
+ td.last-cell:not(:last-child),
1101
+ .pb_table_td.last-cell:not(:last-child) {
1102
+ box-shadow: 1px 0 0 0 var(--column-border-color) !important;
1103
+ }
1104
+ }
1105
+ }
1016
1106
  }
1017
1107
  }
1018
1108
  }
@@ -29,5 +29,167 @@
29
29
  label: "Graduated Students",
30
30
  }
31
31
  ] %>
32
+ <%= pb_rails("caption", props: { text: "Advanced Table Vertical Border Table Props" }) %>
33
+ <%= pb_rails("advanced_table", props: { id: "table_props_table", table_data: @table_data, margin_bottom: "md", column_definitions: column_definitions, table_props: { vertical_border: true, container: false }}) %>
32
34
 
33
- <%= pb_rails("advanced_table", props: { id: "table_props_table", table_data: @table_data, column_definitions: column_definitions, table_props: { vertical_border: true, container: false }}) %>
35
+ <% column_definitions_two = [
36
+ {
37
+ accessor: "year",
38
+ label: "Year",
39
+ cellAccessors: ["quarter", "month", "day"],
40
+ },
41
+ {
42
+ label: "Enrollment Data",
43
+ columns: [
44
+ {
45
+ accessor: "newEnrollments",
46
+ label: "New Enrollments",
47
+ },
48
+ {
49
+ accessor: "scheduledMeetings",
50
+ label: "Scheduled Meetings",
51
+ },
52
+ ],
53
+ },
54
+ {
55
+ label: "Performance Data",
56
+ columns: [
57
+ {
58
+ accessor: "attendanceRate",
59
+ label: "Attendance Rate",
60
+ },
61
+ {
62
+ accessor: "completedClasses",
63
+ label: "Completed Classes",
64
+ },
65
+ {
66
+ accessor: "classCompletionRate",
67
+ label: "Class Completion Rate",
68
+ },
69
+ {
70
+ accessor: "graduatedStudents",
71
+ label: "Graduated Students",
72
+ },
73
+ ],
74
+ },
75
+ ] %>
76
+ <%= pb_rails("caption", props: { text: "Advanced Table Vertical Border Multi Header" }) %>
77
+ <%= pb_rails("advanced_table", props: { id: "table_multi_headers_vertical_borders", margin_bottom: "md", table_data: @table_data, column_definitions: column_definitions_two, table_props: { vertical_border: true } }) %>
78
+
79
+ <% column_definitions_three = [
80
+ {
81
+ accessor: "year",
82
+ label: "Year",
83
+ cellAccessors: ["quarter", "month", "day"],
84
+ },
85
+ {
86
+ label: "Enrollment Data",
87
+ columns: [
88
+ {
89
+ label: "Enrollment Stats",
90
+ columns: [
91
+ {
92
+ accessor: "newEnrollments",
93
+ label: "New Enrollments",
94
+ },
95
+ {
96
+ accessor: "scheduledMeetings",
97
+ label: "Scheduled Meetings",
98
+ },
99
+ ],
100
+ },
101
+ ],
102
+ },
103
+ {
104
+ label: "Performance Data",
105
+ columns: [
106
+ {
107
+ label: "Completion Metrics",
108
+ columns: [
109
+ {
110
+ accessor: "completedClasses",
111
+ label: "Completed Classes",
112
+ },
113
+ {
114
+ accessor: "classCompletionRate",
115
+ label: "Class Completion Rate",
116
+ },
117
+ ],
118
+ },
119
+ {
120
+ label: "Attendance",
121
+ columns: [
122
+ {
123
+ accessor: "attendanceRate",
124
+ label: "Attendance Rate",
125
+ },
126
+ {
127
+ accessor: "scheduledMeetings",
128
+ label: "Scheduled Meetings",
129
+ },
130
+ ],
131
+ },
132
+ ],
133
+ },
134
+ ] %>
135
+ <%= pb_rails("caption", props: { text: "Advanced Table Vertical Border Multi Header with Column Group Border Color" }) %>
136
+ <%= pb_rails("advanced_table", props: { id: "beta_table_with_color_headers", margin_bottom: "md", table_data: @table_data, column_definitions: column_definitions_three, column_group_border_color: "text_lt_default", table_props: { vertical_border: true } }) %>
137
+
138
+ <% column_definitions_four = [
139
+ {
140
+ accessor: "year",
141
+ label: "Year",
142
+ cellAccessors: ["quarter", "month", "day"],
143
+ },
144
+ {
145
+ label: "Enrollment Data",
146
+ columns: [
147
+ {
148
+ label: "Enrollment Stats",
149
+ columns: [
150
+ {
151
+ accessor: "newEnrollments",
152
+ label: "New Enrollments",
153
+ },
154
+ {
155
+ accessor: "scheduledMeetings",
156
+ label: "Scheduled Meetings",
157
+ },
158
+ ],
159
+ },
160
+ ],
161
+ },
162
+ {
163
+ label: "Performance Data",
164
+ columns: [
165
+ {
166
+ label: "Completion Metrics",
167
+ columns: [
168
+ {
169
+ accessor: "completedClasses",
170
+ label: "Completed Classes",
171
+ },
172
+ {
173
+ accessor: "classCompletionRate",
174
+ label: "Class Completion Rate",
175
+ },
176
+ ],
177
+ },
178
+ {
179
+ label: "Attendance",
180
+ columns: [
181
+ {
182
+ accessor: "attendanceRate",
183
+ label: "Attendance Rate",
184
+ },
185
+ {
186
+ accessor: "scheduledMeetings",
187
+ label: "Scheduled Meetings",
188
+ },
189
+ ],
190
+ },
191
+ ],
192
+ },
193
+ ] %>
194
+ <%= pb_rails("caption", props: { text: "Advanced Table Vertical Border Multi Header No Vertical Border" }) %>
195
+ <%= pb_rails("advanced_table", props: {id: "beta_table_with_muilti_headers", table_data: @table_data, column_definitions: column_definitions_four }) %>
@@ -1,6 +1,7 @@
1
1
  import React from "react"
2
2
  import AdvancedTable from '../../pb_advanced_table/_advanced_table'
3
3
  import MOCK_DATA from "./advanced_table_mock_data.json"
4
+ import Caption from "../../pb_caption/_caption"
4
5
 
5
6
  const AdvancedTableTableProps = (props) => {
6
7
  const columnDefinitions = [
@@ -40,14 +41,203 @@ const AdvancedTableTableProps = (props) => {
40
41
  verticalBorder: true
41
42
  }
42
43
 
44
+ const columnDefinitionsTwo = [
45
+ {
46
+ accessor: "year",
47
+ label: "Year",
48
+ cellAccessors: ["quarter", "month", "day"],
49
+ },
50
+ {
51
+ label: "Enrollment Data",
52
+ columns: [
53
+ {
54
+ accessor: "newEnrollments",
55
+ label: "New Enrollments",
56
+ },
57
+ {
58
+ accessor: "scheduledMeetings",
59
+ label: "Scheduled Meetings",
60
+ },
61
+ ],
62
+ },
63
+ {
64
+ label: "Performance Data",
65
+ columns: [
66
+ {
67
+ accessor: "attendanceRate",
68
+ label: "Attendance Rate",
69
+ },
70
+ {
71
+ accessor: "completedClasses",
72
+ label: "Completed Classes",
73
+ },
74
+ {
75
+ accessor: "classCompletionRate",
76
+ label: "Class Completion Rate",
77
+ },
78
+ {
79
+ accessor: "graduatedStudents",
80
+ label: "Graduated Students",
81
+ },
82
+ ],
83
+ },
84
+ ];
85
+
86
+ const tablePropsTwo = {
87
+ verticalBorder: true,
88
+ }
89
+
90
+ const columnDefinitionsThree = [
91
+ {
92
+ accessor: "year",
93
+ label: "Year",
94
+ cellAccessors: ["quarter", "month", "day"],
95
+ },
96
+ {
97
+ label: "Enrollment Data",
98
+ columns: [
99
+ {
100
+ label: "Enrollment Stats",
101
+ columns: [
102
+ {
103
+ accessor: "newEnrollments",
104
+ label: "New Enrollments",
105
+ },
106
+ {
107
+ accessor: "scheduledMeetings",
108
+ label: "Scheduled Meetings",
109
+ },
110
+ ],
111
+ },
112
+ ],
113
+ },
114
+ {
115
+ label: "Performance Data",
116
+ columns: [
117
+ {
118
+ label: "Completion Metrics",
119
+ columns: [
120
+ {
121
+ accessor: "completedClasses",
122
+ label: "Completed Classes",
123
+ },
124
+ {
125
+ accessor: "classCompletionRate",
126
+ label: "Class Completion Rate",
127
+ },
128
+ ],
129
+ },
130
+ {
131
+ label: "Attendance",
132
+ columns: [
133
+ {
134
+ accessor: "attendanceRate",
135
+ label: "Attendance Rate",
136
+ },
137
+ {
138
+ accessor: "scheduledMeetings",
139
+ label: "Scheduled Meetings",
140
+ },
141
+ ],
142
+ },
143
+ ],
144
+ },
145
+ ];
146
+
147
+ const tablePropsThree = {
148
+ verticalBorder: true
149
+ }
150
+
151
+ const columnDefinitionsFour = [
152
+ {
153
+ accessor: "year",
154
+ label: "Year",
155
+ cellAccessors: ["quarter", "month", "day"],
156
+ },
157
+ {
158
+ label: "Enrollment Data",
159
+ columns: [
160
+ {
161
+ label: "Enrollment Stats",
162
+ columns: [
163
+ {
164
+ accessor: "newEnrollments",
165
+ label: "New Enrollments",
166
+ },
167
+ {
168
+ accessor: "scheduledMeetings",
169
+ label: "Scheduled Meetings",
170
+ },
171
+ ],
172
+ },
173
+ ],
174
+ },
175
+ {
176
+ label: "Performance Data",
177
+ columns: [
178
+ {
179
+ label: "Completion Metrics",
180
+ columns: [
181
+ {
182
+ accessor: "completedClasses",
183
+ label: "Completed Classes",
184
+ },
185
+ {
186
+ accessor: "classCompletionRate",
187
+ label: "Class Completion Rate",
188
+ },
189
+ ],
190
+ },
191
+ {
192
+ label: "Attendance",
193
+ columns: [
194
+ {
195
+ accessor: "attendanceRate",
196
+ label: "Attendance Rate",
197
+ },
198
+ {
199
+ accessor: "scheduledMeetings",
200
+ label: "Scheduled Meetings",
201
+ },
202
+ ],
203
+ },
204
+ ],
205
+ },
206
+ ];
207
+
43
208
  return (
44
209
  <div>
210
+ <Caption text="Advanced Table Vertical Border Table Props" />
45
211
  <AdvancedTable
46
212
  columnDefinitions={columnDefinitions}
213
+ marginBottom="md"
47
214
  tableData={MOCK_DATA}
48
215
  tableProps={tableProps}
49
216
  {...props}
50
217
  />
218
+ <Caption text="Advanced Table Vertical Border Multi Header" />
219
+ <AdvancedTable
220
+ columnDefinitions={columnDefinitionsTwo}
221
+ marginBottom="md"
222
+ tableData={MOCK_DATA}
223
+ tableProps={tablePropsTwo}
224
+ {...props}
225
+ />
226
+ <Caption text="Advanced Table Vertical Border Multi Header with Column Group Border Color" />
227
+ <AdvancedTable
228
+ columnDefinitions={columnDefinitionsThree}
229
+ columnGroupBorderColor="text_lt_default"
230
+ marginBottom="md"
231
+ tableData={MOCK_DATA}
232
+ tableProps={tablePropsThree}
233
+ {...props}
234
+ />
235
+ <Caption text="Advanced Table Vertical Border Multi Header No Vertical Border" />
236
+ <AdvancedTable
237
+ columnDefinitions={columnDefinitionsFour}
238
+ tableData={MOCK_DATA}
239
+ {...props}
240
+ />
51
241
  </div>
52
242
  )
53
243
  }
@@ -30,9 +30,9 @@ const reducer = (state: InitialStateType, action: ActionType) => {
30
30
  case 'REORDER_ITEMS': {
31
31
  const { dragId, targetId } = action.payload;
32
32
  const newItems = [...state.items];
33
- const draggedItem = newItems.find(item => item && item.id === dragId);
33
+ const draggedItem = newItems.find(item => item.id === dragId);
34
34
  const draggedIndex = newItems.indexOf(draggedItem);
35
- const targetIndex = newItems.findIndex(item => item && item.id === targetId);
35
+ const targetIndex = newItems.findIndex(item => item.id === targetId);
36
36
 
37
37
  newItems.splice(draggedIndex, 1);
38
38
  newItems.splice(targetIndex, 0, draggedItem);
@@ -144,6 +144,7 @@ export const DraggableProvider = ({
144
144
  }, [state.items]);
145
145
 
146
146
  const handleDragStart = (id: string, container: string) => {
147
+ console.log('[Draggable] handleDragStart:', { id, container, providerId });
147
148
  dispatch({ type: 'SET_DRAG_DATA', payload: { id: id, initialGroup: container, originId: providerId } });
148
149
  dispatch({ type: 'SET_IS_DRAGGING', payload: id });
149
150
  if (onDragStart) onDragStart(id, container);
@@ -155,6 +156,7 @@ export const DraggableProvider = ({
155
156
  if (state.dragData.id !== id) {
156
157
  // Check if this is a cross-container drag
157
158
  const isCrossContainer = state.dragData.initialGroup !== container;
159
+ console.log('[Draggable] handleDragEnter:', { id, container, isCrossContainer, draggedId: state.dragData.id });
158
160
 
159
161
  if (isCrossContainer) {
160
162
  // Use cross-container reorder to update container temporarily for dropzone preview
@@ -172,7 +174,10 @@ export const DraggableProvider = ({
172
174
  const draggedItemId = state.dragData.id;
173
175
  const originalContainer = state.dragData.initialGroup;
174
176
 
177
+ console.log('[Draggable] handleDragEnd:', { draggedItemId, originalContainer });
178
+
175
179
  if (!draggedItemId) {
180
+ console.warn('[Draggable] handleDragEnd: No draggedItemId found');
176
181
  dispatch({ type: 'SET_IS_DRAGGING', payload: "" });
177
182
  dispatch({ type: 'SET_ACTIVE_CONTAINER', payload: "" });
178
183
  dispatch({ type: 'SET_DRAG_DATA', payload: { id: "", initialGroup: "", originId: "" } });
@@ -182,9 +187,11 @@ export const DraggableProvider = ({
182
187
  const draggedItem = state.items.find(item => item && item.id === draggedItemId);
183
188
  const finalContainer = draggedItem ? draggedItem.container : originalContainer;
184
189
 
190
+ console.log('[Draggable] handleDragEnd item found:', { draggedItem: !!draggedItem, finalContainer });
191
+
185
192
  // Find items above and below in the same container
186
- const itemsInContainer = state.items.filter(item => item.container === finalContainer);
187
- const indexInContainer = itemsInContainer.findIndex(item => item.id === draggedItemId);
193
+ const itemsInContainer = state.items.filter(item => item && item.container === finalContainer);
194
+ const indexInContainer = itemsInContainer.findIndex(item => item && item.id === draggedItemId);
188
195
  const itemAbove = indexInContainer > 0 ? itemsInContainer[indexInContainer - 1] : null;
189
196
  const itemBelow = indexInContainer < itemsInContainer.length - 1 ? itemsInContainer[indexInContainer + 1] : null;
190
197
 
@@ -206,21 +213,33 @@ export const DraggableProvider = ({
206
213
  const draggedItemId = state.dragData.id;
207
214
  const originalContainer = state.dragData.initialGroup;
208
215
 
209
- if (!draggedItemId) return; // Guard against missing drag data when dropping too quickly
216
+ console.log('[Draggable] handleDrop:', { draggedItemId, container, originalContainer });
217
+
218
+ if (!draggedItemId) {
219
+ console.warn('[Draggable] handleDrop: No draggedItemId found');
220
+ return; // Guard against missing drag data when dropping too quickly
221
+ }
210
222
 
211
223
  const draggedItem = state.items.find(item => item && item.id === draggedItemId);
212
224
 
213
225
  if (!draggedItem) {
214
- // Item not found in state - clear drag state and exit
226
+ console.error('[Draggable] handleDrop: Item not found in state', { draggedItemId, itemsCount: state.items.length });
227
+ // Item not found in state: clear drag state and exit
215
228
  dispatch({ type: 'SET_IS_DRAGGING', payload: "" });
216
229
  dispatch({ type: 'SET_ACTIVE_CONTAINER', payload: "" });
217
230
  dispatch({ type: 'SET_DRAG_DATA', payload: { id: "", initialGroup: "", originId: "" } });
218
231
  return;
219
232
  }
220
233
 
221
- // Find items above and below in the same container (before changeCategory updates it)
222
- const itemsInContainer = state.items.filter(item => item.container === container);
223
- const indexInContainer = itemsInContainer.findIndex(item => item.id === draggedItemId);
234
+ // If dropping in a different container and item hasn't been moved there yet, move to end
235
+ if (container !== originalContainer && draggedItem.container !== container) {
236
+ console.log('[Draggable] handleDrop: Moving to container end');
237
+ dispatch({ type: 'MOVE_TO_CONTAINER_END', payload: { dragId: draggedItemId, newContainer: container } });
238
+ }
239
+
240
+ // Find items above and below in the same container
241
+ const itemsInContainer = state.items.filter(item => item && item.container === container);
242
+ const indexInContainer = itemsInContainer.findIndex(item => item && item.id === draggedItemId);
224
243
  const itemAbove = indexInContainer > 0 ? itemsInContainer[indexInContainer - 1] : null;
225
244
  const itemBelow = indexInContainer < itemsInContainer.length - 1 ? itemsInContainer[indexInContainer + 1] : null;
226
245
 
@@ -230,7 +249,7 @@ export const DraggableProvider = ({
230
249
  changeCategory(draggedItemId, container);
231
250
 
232
251
  // Pass enhanced info to onDrop callback so devs have more context
233
- if (onDrop) {
252
+ if (onDrop && draggedItem) {
234
253
  const updatedItem = { ...draggedItem, container };
235
254
  onDrop(draggedItemId, container, originalContainer, updatedItem, itemAbove, itemBelow);
236
255
  }
@@ -240,25 +259,22 @@ export const DraggableProvider = ({
240
259
  if (state.dragData.originId !== providerId) return; // Ignore drag over events from other providers
241
260
 
242
261
  e.preventDefault();
262
+ dispatch({ type: 'SET_ACTIVE_CONTAINER', payload: container });
243
263
 
244
- // Check if we're dragging over a different container than where the item currently is
245
- if (!state.dragData.id) return; // Guard against missing drag ID when dragging too quickly
264
+ // Guard against missing drag ID
265
+ if (!state.dragData.id) return;
246
266
 
267
+ // Find the dragged item
247
268
  const draggedItem = state.items.find(item => item && item.id === state.dragData.id);
248
269
 
249
- // Only update if item exists and needs to move to a different container
270
+ // Only move to container end if item exists and is in a different container
250
271
  if (draggedItem && draggedItem.container !== container) {
251
- // Only dispatch if we're not already in the process of updating to this container
252
- // This is needed to prevent multiple rapid MOVE_TO_CONTAINER_END actions that can cause race conditions + errors (Not seen in PB, errors show up in Nitro console)
253
- if (state.activeContainer !== container) {
254
- dispatch({ type: 'SET_ACTIVE_CONTAINER', payload: container });
255
- // This handles the case when dragging to empty space at bottom of container OR in empty container
256
- dispatch({ type: 'MOVE_TO_CONTAINER_END', payload: { dragId: state.dragData.id, newContainer: container } });
257
- dispatch({ type: 'SET_DRAG_DATA', payload: { id: state.dragData.id, initialGroup: container, originId: providerId } });
258
- }
259
- } else if (state.activeContainer !== container) {
260
- // Just update active container if item is already in correct container
261
- dispatch({ type: 'SET_ACTIVE_CONTAINER', payload: container });
272
+ console.log('[Draggable] handleDragOver: Moving to container end', { dragId: state.dragData.id, fromContainer: draggedItem.container, toContainer: container });
273
+ // Move item to end of target container for preview
274
+ dispatch({ type: 'MOVE_TO_CONTAINER_END', payload: { dragId: state.dragData.id, newContainer: container } });
275
+ dispatch({ type: 'SET_DRAG_DATA', payload: { id: state.dragData.id, initialGroup: container, originId: providerId } });
276
+ } else if (!draggedItem) {
277
+ console.error('[Draggable] handleDragOver: Item not found', { dragId: state.dragData.id, itemsCount: state.items.length });
262
278
  }
263
279
 
264
280
  if (onDragOver) onDragOver(e, container);