github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/ui/src/components/downloadFile/downloadFile.tsx (about) 1 // Copyright 2020 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 import React, { useRef, useEffect, forwardRef, useImperativeHandle } from "react"; 12 13 type FileTypes = "text/plain" | "application/json"; 14 15 export interface DownloadAsFileProps { 16 fileName?: string; 17 fileType?: FileTypes; 18 content?: string; 19 } 20 21 export interface DownloadFileRef { 22 download: (name: string, type: FileTypes, body: string) => void; 23 } 24 25 /* 26 * DownloadFile can download file in two modes `default` and `imperative`. 27 * `Default` mode - when DownloadFile wraps component which should trigger 28 * downloading and can work only if content of file is already available. 29 * 30 * For example: 31 * ``` 32 * <DownloadFile fileName="example.txt" fileType="text/plain" content="Some text"> 33 * <button>Download</download> 34 * </DownloadFile> 35 * ``` 36 * 37 * `Imperative` mode allows initiate file download in async way, and trigger 38 * download manually. 39 * 40 * For example: 41 * ``` 42 * downloadRef = React.createRef<DownloadFileRef>(); 43 * 44 * fetchData = () => { 45 * Promise.resolve().then((someText) => 46 * this.downloadRef.current.download("example.txt", "text/plain", someText)) 47 * } 48 * 49 * <DownloadFile ref={downloadRef} /> 50 * <button onClick={fetchData}>Download</button> 51 * ``` 52 * */ 53 // tslint:disable-next-line:variable-name 54 export const DownloadFile = forwardRef<DownloadFileRef, DownloadAsFileProps>((props, ref) => { 55 const { children, fileName, fileType, content } = props; 56 const anchorRef = useRef<HTMLAnchorElement>(); 57 58 const bootstrapFile = (name: string, type: FileTypes, body: string) => { 59 const anchorElement = anchorRef.current; 60 const file = new Blob([body], { type }); 61 anchorElement.href = URL.createObjectURL(file); 62 anchorElement.download = name; 63 }; 64 65 useEffect( 66 () => { 67 if (content === undefined) { 68 return; 69 } 70 bootstrapFile(fileName, fileType, content); 71 }, 72 [fileName, fileType, content], 73 ); 74 75 useImperativeHandle(ref, () => ({ 76 download: (name: string, type: FileTypes, body: string) => { 77 bootstrapFile(name, type, body); 78 anchorRef.current.click(); 79 }, 80 })); 81 82 return ( 83 <a ref={anchorRef}> 84 {children} 85 </a> 86 ); 87 });