@@ -14,7 +14,7 @@ import {
1414 TreeView ,
1515 InlineNotification
1616} from '@carbon/react' ;
17- import { Copy } from '@carbon/react/icons' ;
17+ import { Copy , Download } from '@carbon/react/icons' ;
1818import { css } from 'emotion' ;
1919import Editor , { useMonaco } from '@monaco-editor/react' ;
2020
@@ -30,6 +30,7 @@ import { GlobalStateContext } from '../../../../context';
3030import { ExportImageComponent } from './export-image-component' ;
3131import { filenameToLanguage , getFragmentJsonExportString } from '@carbon-builder/sdk-react' ;
3232import JSONCrush from 'jsoncrush' ;
33+ import JSZip from 'jszip' ;
3334
3435const exportCodeModalStyle = css `
3536 .cds--tab-content {
@@ -88,6 +89,17 @@ const versionDropdownStyle = css`
8889 right : 1rem ;
8990` ;
9091
92+ const addToZip = ( parent : JSZip , items : any [ ] ) => {
93+ items . forEach ( item => {
94+ if ( item . items && item . items . length ) {
95+ const folder = parent . folder ( item . name ) ;
96+ addToZip ( folder as JSZip , item . items ) ;
97+ } else {
98+ parent . file ( item . name , item . code ) ;
99+ }
100+ } ) ;
101+ } ;
102+
91103const renderCodeTree = ( nodes : any , path = '' ) => {
92104 if ( ! nodes ) {
93105 return ;
@@ -109,7 +121,26 @@ const renderCodeTree = (nodes: any, path = '') => {
109121 renderIcon = { icon }
110122 isExpanded = { isExpanded }
111123 value = { code }
112- label = { name }
124+ className = { css `.cds--tree-node__icon { align-self : center; }` }
125+ label = { < >
126+ { name }
127+ {
128+ items && items . length > 0 &&
129+ < Button
130+ hasIconOnly
131+ onClick = { ( ) => {
132+ const zip = new JSZip ( ) ;
133+ addToZip ( zip , items ) ;
134+ zip . generateAsync ( { type : 'blob' } ) . then ( content => {
135+ saveBlob ( content , `${ name } .zip` ) ;
136+ } ) ;
137+ } }
138+ iconDescription = 'Download as ZIP'
139+ className = { css `margin-left : 0.5rem ;` }
140+ kind = 'ghost'
141+ size = 'sm'
142+ renderIcon = { Download } /> }
143+ </ > }
113144 { ...nodeProps } >
114145 { renderCodeTree ( items , fullPath ) }
115146 </ TreeNode > ;
@@ -228,7 +259,7 @@ export const ExportModal = () => {
228259 }
229260
230261 setSelectedAngularFileItem ( fileItem || selectedAngularFileItem ) ;
231- // eslint-disable-next-line react-hooks/exhaustive-deps
262+ // eslint-disable-next-line react-hooks/exhaustive-deps
232263 } , [ angularCode , fragmentExportModal . isVisible ] ) ;
233264
234265 useEffect ( ( ) => {
@@ -297,10 +328,10 @@ export const ExportModal = () => {
297328 {
298329 fragmentExportModal . isVisible &&
299330 < Tabs
300- selectedIndex = { + settings ?. selectedExportTabIndex || 0 }
301- onChange = { ( { selectedIndex } : { selectedIndex : number } ) => {
302- setSettings ( { ...settings , selectedExportTabIndex : selectedIndex } ) ;
303- } } >
331+ selectedIndex = { + settings ?. selectedExportTabIndex || 0 }
332+ onChange = { ( { selectedIndex } : { selectedIndex : number } ) => {
333+ setSettings ( { ...settings , selectedExportTabIndex : selectedIndex } ) ;
334+ } } >
304335 < TabList aria-label = 'Export list' className = { tabListStyle } >
305336 < Tab > Angular</ Tab >
306337 < Tab > React</ Tab >
0 commit comments