@@ -30,6 +30,13 @@ interface PageData {
3030 alt : string ;
3131 pageIndex : number ;
3232 src : string ;
33+ rotation : number ;
34+ }
35+
36+ interface DraftPageData extends PageData {
37+ draftRotation ?: number ; // Additional rotation applied in draft state
38+ isNew ?: boolean ;
39+ isRemoved ?: boolean ;
3340}
3441
3542type DocumentOperation =
@@ -40,7 +47,7 @@ type DocumentOperation =
4047const DocumentEditor = ( props : Props ) => {
4148 const { instance } = props ;
4249 const [ pages , setPages ] = useState < PageData [ ] > ( [ ] ) ;
43- // TODO: handle for 'all' selection
50+ const [ draftPages , setDraftPages ] = useState < DraftPageData [ ] > ( [ ] ) ;
4451 const [ selectedKeys , setSelectedKeys ] = useState < Set < string | number > > (
4552 new Set ( ) ,
4653 ) ;
@@ -66,10 +73,12 @@ const DocumentEditor = (props: Props) => {
6673 alt : pageInfo . label ,
6774 pageIndex : pageInfo . index ,
6875 src,
76+ rotation : pageInfo . rotation || 0 ,
6977 } ) ;
7078 }
7179
7280 setPages ( pagesData ) ;
81+ setDraftPages ( pagesData ) ;
7382 } , [ instance ] ) ;
7483
7584 useEffect ( ( ) => {
@@ -91,26 +100,64 @@ const DocumentEditor = (props: Props) => {
91100 pageIndexes : [ ...selectedKeys ] . map ( ( key ) => parseKey ( key ) - 1 ) ,
92101 rotateBy : 90 ,
93102 } ;
103+ // Update draft state
104+ setDraftPages ( ( current ) =>
105+ current . map ( ( page ) =>
106+ selectedKeys . has ( page . id )
107+ ? { ...page , draftRotation : ( page . draftRotation || 0 ) + 90 }
108+ : page ,
109+ ) ,
110+ ) ;
94111 } else if ( operation === "rotate-counterclockwise" ) {
95112 operationData = {
96113 type : "rotatePages" ,
97114 pageIndexes : [ ...selectedKeys ] . map ( ( key ) => parseKey ( key ) - 1 ) ,
98115 rotateBy : 270 ,
99116 } ;
117+ // Update draft state
118+ setDraftPages ( ( current ) =>
119+ current . map ( ( page ) =>
120+ selectedKeys . has ( page . id )
121+ ? { ...page , draftRotation : ( page . draftRotation || 0 ) + 270 }
122+ : page ,
123+ ) ,
124+ ) ;
100125 } else if ( operation === "remove-pages" ) {
101126 operationData = {
102127 type : "removePages" ,
103128 pageIndexes : [ ...selectedKeys ] . map ( ( key ) => parseKey ( key ) - 1 ) ,
104129 } ;
130+ // Update draft state
131+ setDraftPages ( ( current ) =>
132+ current . map ( ( page ) =>
133+ selectedKeys . has ( page . id ) ? { ...page , isRemoved : true } : page ,
134+ ) ,
135+ ) ;
105136 } else if ( operation === "add-page" ) {
137+ const afterIndex = parseKey ( [ ...selectedKeys ] [ 0 ] ) - 1 ;
106138 operationData = {
107139 type : "addPage" ,
108- afterPageIndex : parseKey ( [ ... selectedKeys ] [ 0 ] ) - 1 ,
140+ afterPageIndex : afterIndex ,
109141 backgroundColor : new NutrientViewer . Color ( { r : 255 , g : 255 , b : 255 } ) ,
110142 pageHeight : 400 ,
111143 pageWidth : 300 ,
112144 rotateBy : 0 ,
113145 } ;
146+ // Update draft state
147+ setDraftPages ( ( current ) => {
148+ const newPage : DraftPageData = {
149+ id : `temp-${ Date . now ( ) } ` ,
150+ label : "New Page" ,
151+ alt : "New blank page" ,
152+ pageIndex : afterIndex + 1 ,
153+ src : "" ,
154+ rotation : 0 ,
155+ isNew : true ,
156+ } ;
157+ const result = [ ...current ] ;
158+ result . splice ( afterIndex + 1 , 0 , newPage ) ;
159+ return result ;
160+ } ) ;
114161 }
115162
116163 if ( operationData ) {
@@ -130,6 +177,48 @@ const DocumentEditor = (props: Props) => {
130177 setSelectedKeys ( new Set ( ) ) ;
131178 } ;
132179
180+ const displayPages = draftPages . filter ( ( page ) => ! page . isRemoved ) ;
181+
182+ const renderImage = ( item : {
183+ id : string ;
184+ data ?: { alt ?: string ; src ?: string } ;
185+ } ) => {
186+ // Find the corresponding draft page
187+ const draftPage = displayPages . find ( ( page ) => page . id === item . id ) ;
188+
189+ if ( ! draftPage ) {
190+ return < div > Error: Page not found</ div > ;
191+ }
192+
193+ if ( draftPage . isNew ) {
194+ // Render a white blank page
195+ return (
196+ < div
197+ style = { {
198+ backgroundColor : "white" ,
199+ width : "100%" ,
200+ height : "100%" ,
201+ display : "flex" ,
202+ alignItems : "center" ,
203+ justifyContent : "center" ,
204+ border : "1px solid #e5e7eb" ,
205+ } }
206+ >
207+ < Text > New Page</ Text >
208+ </ div >
209+ ) ;
210+ }
211+
212+ // Apply only draft rotation (the fetched image already has the document rotation applied)
213+ const style = draftPage . draftRotation
214+ ? { transform : `rotate(${ draftPage . draftRotation } deg)` }
215+ : undefined ;
216+
217+ return (
218+ < img src = { draftPage . src } alt = { draftPage . alt } style = { style } width = "100%" />
219+ ) ;
220+ } ;
221+
133222 const selectionText = selectedKeys . size ? (
134223 < Text > { selectedKeys . size } page(s) selected</ Text >
135224 ) : (
@@ -185,14 +274,41 @@ const DocumentEditor = (props: Props) => {
185274 { operations }
186275 < ImageGallery
187276 aria-label = "Document editor sidebar"
188- items = { pages }
277+ items = { displayPages }
189278 imageWidth = "md"
190279 selectionMode = "multiple"
280+ selectedKeys = { selectedKeys }
191281 onSelectionChange = { ( keys ) =>
192282 setSelectedKeys (
193- keys === "all" ? new Set ( pages . map ( ( page ) => page . id ) ) : keys ,
283+ keys === "all"
284+ ? new Set ( displayPages . map ( ( page ) => page . id ) )
285+ : keys ,
194286 )
195287 }
288+ renderImage = { renderImage }
289+ imageDimensions = { ( item ) => {
290+ const draftPage = displayPages . find (
291+ ( page ) => page . id === item . id ,
292+ ) ;
293+ if ( ! draftPage ) {
294+ return { width : 180 , height : 250 } ;
295+ }
296+
297+ // Calculate total rotation (document rotation + draft rotation)
298+ const totalRotation =
299+ draftPage . rotation + ( draftPage . draftRotation || 0 ) ;
300+
301+ // For 90 or 270 degree rotations, swap dimensions
302+ const normalizedRotation = totalRotation % 360 ;
303+ const isRotated90or270 =
304+ normalizedRotation === 90 || normalizedRotation === 270 ;
305+
306+ if ( isRotated90or270 ) {
307+ return { width : 250 , height : 180 } ;
308+ }
309+
310+ return { width : 180 , height : 250 } ;
311+ } }
196312 />
197313 < Box gap = "md" display = "flex" >
198314 < ActionButton
0 commit comments