In order to use the SpreadJS File Format feature, you need to add the related js file link into the document's head section below the Spread link. For example:
SpreadJS supports opening and saving sjs file formats. It also supports importing and exporting xlsx, xlsm, xltm, xltx, ssjson, and csv file formats.
For example:
class GC.Spread.Sheets.Workbook
GC.Spread.Sheets.SaveOptions
GC.Spread.Sheets.OpenOptions
GC.Spread.Sheets.ImportOptions
GC.Spread.Sheets.ExportOptions
GC.Spread.Sheets.ExcelFileType
GC.Spread.Sheets.ImportXlsxOptions
GC.Spread.Sheets.ExportXlsxOptions
GC.Spread.Sheets.ImportCsvOptions
.Spread.Sheets.ExportCsvOptions
GC.Spread.Sheets.ImportSSJsonOptions
GC.Spread.Sheets.ExportSSJsonOptions
import * as React from 'react';
import { createRoot } from 'react-dom/client';
import './styles.css';
import { AppFunc } from './app-func';
import { App } from './app-class';
// 1. Functional Component sample
createRoot(document.getElementById('app')).render(<AppFunc />);
// 2. Class Component sample
// createRoot(document.getElementById('app')).render(<App />);
import * as React from 'react';
import GC from '@mescius/spread-sheets';
import '@mescius/spread-sheets-print';
import '@mescius/spread-sheets-io';
import '@mescius/spread-sheets-shapes';
import '@mescius/spread-sheets-charts';
import '@mescius/spread-sheets-slicers';
import '@mescius/spread-sheets-pivot-addon';
import '@mescius/spread-sheets-reportsheet-addon';
import "@mescius/spread-sheets-tablesheet";
import "@mescius/spread-sheets-ganttsheet";
import { SpreadSheets, Worksheet } from '@mescius/spread-sheets-react';
import './styles.css';
window.GC = GC;
function deepClone(obj) {
return JSON.parse(JSON.stringify(obj));
}
function getElementId(mode, fileType, propName) {
return mode + '-' + fileType + '-' + propName;
}
function formatOptionLabel(text) {
return text
.replace(/([a-z])([A-Z])/g, '$1 $2')
.replace(/([0-9])([A-Z][a-z])/g, '$1 $2')
.replace(/\b[a-z]/g, function (letter) {
return letter.toUpperCase();
});
}
function getFileType(file) {
if (!file) {
return;
}
var fileName = file.name;
var extensionName = fileName.substring(fileName.lastIndexOf(".") + 1);
if (extensionName === 'sjs') {
return FileType.SJS;
} else if (extensionName === 'xlsx' || extensionName === 'xlsm' || extensionName === 'xltm' || extensionName === 'xltx') {
return FileType.Excel;
} else if (extensionName === 'ssjson' || extensionName === 'json') {
return FileType.SSJson;
} else if (extensionName === 'csv') {
return FileType.Csv;
}
}
function mapExportFileType(fileType) {
if (fileType === FileType.SSJson) {
return GC.Spread.Sheets.FileType.ssjson;
} else if (fileType === FileType.Csv) {
return GC.Spread.Sheets.FileType.csv;
}
return GC.Spread.Sheets.FileType.excel;
}
function _getElementById(id) {
return document.getElementById(id);
}
var defaultOpenOptions = [
{ propName: "openMode", type: "select", displayText: "OpenMode", options: [{ name: 'normal', value: 0 }, { name: 'lazy', value: 1 }, { name: 'incremental', value: 2 }], default: 0 },
{ propName: "includeStyles", type: "boolean", default: true },
{ propName: "includeFormulas", type: "boolean", default: true },
{ propName: "fullRecalc", type: "boolean", default: false },
{ propName: "dynamicReferences", type: "boolean", default: true },
{ propName: "incrementalCalculation", type: "boolean", default: false },
{ propName: "includeUnusedStyles", type: "boolean", default: true },
];
var importXlsxOptions = [
{ propName: "openMode", type: "select", displayText: "OpenMode", options: [{ name: 'normal', value: 0 }, { name: 'lazy', value: 1 }, { name: 'incremental', value: 2 }], default: 0 },
{ propName: "includeStyles", type: "boolean", default: true },
{ propName: "includeFormulas", type: "boolean", default: true },
{ propName: "frozenColumnsAsRowHeaders", type: "boolean", default: false },
{ propName: "frozenRowsAsColumnHeaders", type: "boolean", default: false },
{ propName: "fullRecalc", type: "boolean", default: false },
{ propName: "dynamicReferences", type: "boolean", default: true },
{ propName: "incrementalCalculation", type: "boolean", default: false },
{ propName: "includeUnusedStyles", type: "boolean", default: true },
{ propName: "convertSheetTableToDataTable", type: "boolean", default: false },
];
var importSSJsonOptions = [
{ propName: "includeStyles", type: "boolean", default: true },
{ propName: "includeFormulas", type: "boolean", default: true },
{ propName: "frozenColumnsAsRowHeaders", type: "boolean", default: false },
{ propName: "frozenRowsAsColumnHeaders", type: "boolean", default: false },
{ propName: "fullRecalc", type: "boolean", default: false },
{ propName: "incrementalLoading", type: "boolean", default: false }
];
var importCsvOptions = [
{ propName: "encoding", type: "string", default: "UTF-8" },
{ propName: "rowDelimiter", type: "string", default: "\r\n" },
{ propName: "columnDelimiter", type: "string", default: "," }
];
var defaultSaveOptions = [
{ propName: "includeBindingSource", type: "boolean", default: false },
{ propName: "includeStyles", type: "boolean", default: true },
{ propName: "includeFormulas", type: "boolean", default: true },
{ propName: "saveAsView", type: "boolean", default: false },
{ propName: "includeAutoMergedCells", type: "boolean", default: false },
{ propName: "includeCalcModelCache", type: "boolean", default: false },
{ propName: "saveR1C1Formula", type: "boolean", default: false },
{ propName: "includeUnusedNames", type: "boolean", default: true },
{ propName: "includeEmptyRegionCells", type: "boolean", default: true },
];
var exportXlsxOptions = [
{ propName: "includeBindingSource", type: "boolean", default: false },
{ propName: "includeStyles", type: "boolean", default: true },
{ propName: "includeFormulas", type: "boolean", default: true },
{ propName: "saveAsView", type: "boolean", default: false },
{ propName: "rowHeadersAsFrozenColumns", type: "boolean", default: false },
{ propName: "columnHeadersAsFrozenRows", type: "boolean", default: false },
{ propName: "includeAutoMergedCells", type: "boolean", default: false },
{ propName: "includeUnusedNames", type: "boolean", default: true },
{ propName: "includeEmptyRegionCells", type: "boolean", default: true },
{ propName: "losslessEditing", type: "boolean", default: true },
];
var exportSSJsonOptions = [
{ propName: "includeBindingSource", type: "boolean", default: false },
{ propName: "includeStyles", type: "boolean", default: true },
{ propName: "includeFormulas", type: "boolean", default: true },
{ propName: "saveAsView", type: "boolean", default: false },
{ propName: "rowHeadersAsFrozenColumns", type: "boolean", default: false },
{ propName: "columnHeadersAsFrozenRows", type: "boolean", default: false },
{ propName: "includeAutoMergedCells", type: "boolean", default: false },
];
var exportCsvOptions = [
{ propName: "encoding", type: "string", default: "UTF-8" },
{ propName: "rowDelimiter", type: "string", default: "\r\n" },
{ propName: "columnDelimiter", type: "string", default: "," },
{ propName: "sheetIndex", type: "number", default: 0 },
{ propName: "row", type: "number", default: 0 },
{ propName: "column", type: "number", default: 0 },
{ propName: "rowCount", type: "number", default: 200 },
{ propName: "columnCount", type: "number", default: 20 },
];
var FileType = {
SJS: 'sjs',
Excel: 'xlsx',
SSJson: 'ssjson',
Csv: 'csv',
}
const ExcelFileType = {
xlsx: 'XLSX',
xlsm: 'XLSM',
xltm: 'XLTM',
xltx: 'XLTX',
}
export function AppFunc() {
const [spread, setSpread] = React.useState(null);
const [selectedFile, setSelectedFile] = React.useState(null);
const [openFileType, setOpenFileType] = React.useState('');
const [saveFileType, setSaveFileType] = React.useState(FileType.SJS);
const [excelFileType, setExcelFileType] = React.useState(ExcelFileType.xlsx);
const [openOptions, setOpenOptions] = React.useState({
sjs: {},
ssjson: {},
xlsx: {},
csv: {},
});
const [saveOptions, setSaveOptions] = React.useState({
sjs: {},
ssjson: {},
xlsx: {},
csv: {},
});
function initSpread(spread) {
setSpread(spread);
//init Status Bar
var statusBar = new GC.Spread.Sheets.StatusBar.StatusBar(document.getElementById('statusBar'));
statusBar.bind(spread);
}
function open() {
var file = selectedFile;
if (!file) {
return;
}
var fileType = getFileType(file);
var options = deepClone(openOptions[fileType]);
if (fileType === FileType.SJS) {
spread.open(file, function () { }, function () { }, options);
} else {
spread.import(file, function () { }, function () { }, options);
}
}
function save() {
var fileType = saveFileType;
var fileName = 'export.' + (fileType === FileType.Excel ? excelFileType.toLowerCase() : fileType);
var options = deepClone(saveOptions[fileType]);
if (fileType === FileType.SJS) {
spread.save(function (blob) { saveAs(blob, fileName); }, function () { }, options);
} else {
if (fileType === FileType.Csv) {
var { sheetIndex, row, rowCount, column, columnCount } = options;
options.range = {
sheetIndex: sheetIndex,
row: row,
rowCount: rowCount,
column: column,
columnCount: columnCount,
};
}
options.fileType = mapExportFileType(fileType);
spread.export(function (blob) { saveAs(blob, fileName); }, function () { }, options);
}
}
function onSelectedFileChange(e) {
let selectedFile = e.target.files[0];
let openFileType = getFileType(selectedFile);
setSelectedFile(selectedFile);
setOpenFileType(openFileType)
}
function onSaveFileTypeChange(e) {
let saveFileType = e.target.value;
setSaveFileType(saveFileType);
}
const onExcelFileTypeChange = (e) => {
const newExcelFileType = e.target.value;
setExcelFileType(newExcelFileType);
saveOptions.xlsx['excelFileType'] = newExcelFileType;
setSaveOptions(saveOptions);
}
function onPropChange(mode, fileType, prop, e) {
let element = e.target;
var value;
if (prop.type === 'boolean') {
value = element.checked;
} else if (prop.type === 'number') {
value = +element.value;
} else if (prop.type === 'string') {
value = element.value;
} else if (prop.type === 'select') {
value = +element.value;
}
if (mode === 'open') {
openOptions[fileType][prop.propName] = value;
setOpenOptions(openOptions);
} else if (mode === 'save') {
saveOptions[fileType][prop.propName] = value;
setSaveOptions(saveOptions);
}
}
function createOptions(options, fileType, mode) {
let selectFileType = mode === 'open' ? openFileType : saveFileType;
let display = selectFileType === fileType ? '' : 'none';
return <div className={fileType} style={{ display }}>
{options.map((prop) => createProp(mode, fileType, prop))}
</div>;
}
function createProp(mode, fileType, prop) {
let id = getElementId(mode, fileType, prop.propName);
if (prop.type === 'select') {
return <item className='item'>
<label for={id}>{formatOptionLabel(prop.displayText || prop.propName)}</label>
<select id={id} defaultValue={prop.default} onChange={(e) => onPropChange(mode, fileType, prop, e)}>
{prop.options.map((p) => <option value={p.value}>{p.name}</option>)}
</select>
</item>
} else if (prop.type === 'boolean') {
return <item className='item'>
<input id={id} type='checkbox' defaultChecked={prop.default} onChange={(e) => onPropChange(mode, fileType, prop, e)}></input>
<label for={id}>{formatOptionLabel(prop.displayText || prop.propName)}</label>
</item>
} else if (prop.type === 'number') {
return <item className='item'>
<label for={id}>{formatOptionLabel(prop.displayText || prop.propName)}</label>
<input id={id} type='number' defaultValue={prop.default} onChange={(e) => onPropChange(mode, fileType, prop, e)}></input>
</item>
} else {
return <item className='item'>
<label for={id}>{formatOptionLabel(prop.displayText || prop.propName)}</label>
<input id={id} type='text' defaultValue={prop.default} onChange={(e) => onPropChange(mode, fileType, prop, e)}></input>
</item>
}
}
return <div class="sample-tutorial">
<div class="sample-container">
<div class="sample-spreadsheets">
<SpreadSheets workbookInitialized={spread => initSpread(spread)}>
<Worksheet>
</Worksheet>
</SpreadSheets>
</div>
<div id="statusBar"></div>
</div>
<aside className="options-container" aria-label="SpreadJS file format settings">
<div class="panel-header">
<h1>File Format Settings</h1>
<p class="panel-description">Open and save SpreadJS file or Excel file with format-specific import and export options.</p>
</div>
<div className="option-row">
<section class="inputContainer control-section">
<h2>Open File</h2>
<div class="file-action-row">
<label for="selectedFile">Source File</label>
<input id="selectedFile" type="file" accept=".sjs, .xlsx, .xlsm, .xltm, .xltx, .ssjson, .json, .csv" onChange={onSelectedFileChange} />
<button class="settingButton" id="open" onClick={open}>Open</button>
</div>
<div class="open-options">
{[
createOptions(defaultOpenOptions, FileType.SJS, 'open'),
createOptions(importXlsxOptions, FileType.Excel, 'open'),
createOptions(importSSJsonOptions, FileType.SSJson, 'open'),
createOptions(importCsvOptions, FileType.Csv, 'open'),
]}
</div>
</section>
<section class="inputContainer control-section">
<h2>Save File</h2>
<div class="save-action-row">
<label for="saveFileType">File Type</label>
<select id="saveFileType" value={saveFileType} onChange={onSaveFileTypeChange}>
<option value="sjs">SJS</option>
<option value="xlsx">Excel</option>
<option value="ssjson">SSJSON</option>
<option value="csv">CSV</option>
</select>
<button class="settingButton" id="save" onClick={save}>Save</button>
</div>
{saveFileType === FileType.Excel && <div class="excelFileTypeContainer">
<label for="saveExcelFileType">Excel File Type</label>
<div>
<select id="saveExcelFileType" value={excelFileType} onChange={onExcelFileTypeChange}>
<option value="XLSX">Workbook (*.xlsx)</option>
<option value="XLSM">Macro-Enabled Workbook (*.xlsm)</option>
<option value="XLTM">Macro-Enabled Template (*.xltm)</option>
<option value="XLTX">Workbook Template (*.xltx)</option>
</select>
</div>
</div>}
<div class="save-options">
{[
createOptions(defaultSaveOptions, FileType.SJS, 'save'),
createOptions(exportXlsxOptions, FileType.Excel, 'save'),
createOptions(exportSSJsonOptions, FileType.SSJson, 'save'),
createOptions(exportCsvOptions, FileType.Csv, 'save'),
]}
</div>
</section>
</div>
</aside>
</div>;
}
import * as React from 'react';
import { createRoot } from 'react-dom/client';
import { SpreadSheets, Worksheet } from '@mescius/spread-sheets-react';
import GC from '@mescius/spread-sheets';
import '@mescius/spread-sheets-print';
import '@mescius/spread-sheets-io';
import '@mescius/spread-sheets-shapes';
import '@mescius/spread-sheets-charts';
import '@mescius/spread-sheets-slicers';
import '@mescius/spread-sheets-pivot-addon';
import '@mescius/spread-sheets-reportsheet-addon';
import "@mescius/spread-sheets-tablesheet";
import "@mescius/spread-sheets-ganttsheet";
import './styles.css';
const Component = React.Component;
window.GC = GC;
var openOptions = [
{ propName: "openMode", type: "select", displayText: "OpenMode", options: [{name: 'normal', value: 0}, {name: 'lazy', value: 1}, {name: 'incremental', value: 2}], default: 0 },
{ propName: "includeStyles", type: "boolean", default: true },
{ propName: "includeFormulas", type: "boolean", default: true },
{ propName: "fullRecalc", type: "boolean", default: false },
{ propName: "dynamicReferences", type: "boolean", default: true },
{ propName: "incrementalCalculation", type: "boolean", default: false },
{ propName: "includeUnusedStyles", type: "boolean", default: true },
];
var importXlsxOptions = [
{ propName: "openMode", type: "select", displayText: "OpenMode", options: [{name: 'normal', value: 0}, {name: 'lazy', value: 1}, {name: 'incremental', value: 2}], default: 0 },
{ propName: "includeStyles", type: "boolean", default: true },
{ propName: "includeFormulas", type: "boolean", default: true },
{ propName: "frozenColumnsAsRowHeaders", type: "boolean", default: false },
{ propName: "frozenRowsAsColumnHeaders", type: "boolean", default: false },
{ propName: "fullRecalc", type: "boolean", default: false },
{ propName: "dynamicReferences", type: "boolean", default: true },
{ propName: "incrementalCalculation", type: "boolean", default: false },
{ propName: "includeUnusedStyles", type: "boolean", default: true },
{ propName: "convertSheetTableToDataTable", type: "boolean", default: false },
];
var importSSJsonOptions = [
{ propName: "includeStyles", type: "boolean", default: true },
{ propName: "includeFormulas", type: "boolean", default: true },
{ propName: "frozenColumnsAsRowHeaders", type: "boolean", default: false },
{ propName: "frozenRowsAsColumnHeaders", type: "boolean", default: false },
{ propName: "fullRecalc", type: "boolean", default: false },
{ propName: "incrementalLoading", type: "boolean", default: false }
];
var importCsvOptions = [
{ propName: "encoding", type: "string", default: "UTF-8" },
{ propName: "rowDelimiter", type: "string", default: "\r\n" },
{ propName: "columnDelimiter", type: "string", default: "," }
];
var saveOptions = [
{ propName: "includeBindingSource", type: "boolean", default: false },
{ propName: "includeStyles", type: "boolean", default: true },
{ propName: "includeFormulas", type: "boolean", default: true },
{ propName: "saveAsView", type: "boolean", default: false },
{ propName: "includeAutoMergedCells", type: "boolean", default: false },
{ propName: "includeCalcModelCache", type: "boolean", default: false },
{ propName: "saveR1C1Formula", type: "boolean", default: false },
{ propName: "includeUnusedNames", type: "boolean", default: true },
{ propName: "includeEmptyRegionCells", type: "boolean", default: true },
];
var exportXlsxOptions = [
{ propName: "includeBindingSource", type: "boolean", default: false },
{ propName: "includeStyles", type: "boolean", default: true },
{ propName: "includeFormulas", type: "boolean", default: true },
{ propName: "saveAsView", type: "boolean", default: false },
{ propName: "rowHeadersAsFrozenColumns", type: "boolean", default: false },
{ propName: "columnHeadersAsFrozenRows", type: "boolean", default: false },
{ propName: "includeAutoMergedCells", type: "boolean", default: false },
{ propName: "includeUnusedNames", type: "boolean", default: true },
{ propName: "includeEmptyRegionCells", type: "boolean", default: true },
{ propName: "losslessEditing", type: "boolean", default: true },
];
var exportSSJsonOptions = [
{ propName: "includeBindingSource", type: "boolean", default: false },
{ propName: "includeStyles", type: "boolean", default: true },
{ propName: "includeFormulas", type: "boolean", default: true },
{ propName: "saveAsView", type: "boolean", default: false },
{ propName: "rowHeadersAsFrozenColumns", type: "boolean", default: false },
{ propName: "columnHeadersAsFrozenRows", type: "boolean", default: false },
{ propName: "includeAutoMergedCells", type: "boolean", default: false },
];
var exportCsvOptions = [
{ propName: "encoding", type: "string", default: "UTF-8" },
{ propName: "rowDelimiter", type: "string", default: "\r\n" },
{ propName: "columnDelimiter", type: "string", default: "," },
{ propName: "sheetIndex", type: "number", default: 0 },
{ propName: "row", type: "number", default: 0 },
{ propName: "column", type: "number", default: 0 },
{ propName: "rowCount", type: "number", default: 200 },
{ propName: "columnCount", type: "number", default: 20 },
];
var FileType = {
SJS: 'sjs',
Excel: 'xlsx',
SSJson: 'ssjson',
Csv: 'csv',
}
const ExcelFileType = {
xlsx : 'XLSX',
xlsm : 'XLSM',
xltm : 'XLTM',
xltx : 'XLTX',
}
function deepClone (obj) {
return JSON.parse(JSON.stringify(obj));
}
function getElementId (mode, fileType, propName) {
return mode + '-' + fileType + '-' + propName;
}
function formatOptionLabel(text) {
return text
.replace(/([a-z])([A-Z])/g, '$1 $2')
.replace(/([0-9])([A-Z][a-z])/g, '$1 $2')
.replace(/\b[a-z]/g, function (letter) {
return letter.toUpperCase();
});
}
function getFileType (file) {
if (!file) {
return;
}
var fileName = file.name;
var extensionName = fileName.substring(fileName.lastIndexOf(".") + 1);
if (extensionName === 'sjs') {
return FileType.SJS;
} else if (extensionName === 'xlsx' || extensionName === 'xlsm' || extensionName === 'xltm' || extensionName === 'xltx') {
return FileType.Excel;
} else if (extensionName === 'ssjson' || extensionName === 'json') {
return FileType.SSJson;
} else if (extensionName === 'csv') {
return FileType.Csv;
}
}
function mapExportFileType (fileType) {
if (fileType === FileType.SSJson) {
return GC.Spread.Sheets.FileType.ssjson;
} else if (fileType === FileType.Csv) {
return GC.Spread.Sheets.FileType.csv;
}
return GC.Spread.Sheets.FileType.excel;
}
function _getElementById(id) {
return document.getElementById(id);
}
export class App extends Component {
constructor(props) {
super(props);
this.spread = null;
this.state = {
selectedFile: null,
openFileType: '',
saveFileType: FileType.SJS,
excelFileType: ExcelFileType.xlsx,
openOptions: {
sjs: {},
ssjson: {},
xlsx: {},
csv: {},
},
saveOptions: {
sjs: {},
ssjson: {},
xlsx: {},
csv: {},
}
};
this.open = this.open.bind(this);
this.save = this.save.bind(this);
this.onSelectedFileChange = this.onSelectedFileChange.bind(this);
this.onSaveFileTypeChange = this.onSaveFileTypeChange.bind(this);
this.onExcelFileTypeChange = this.onExcelFileTypeChange.bind(this);
this.onPropChange = this.onPropChange.bind(this);
}
render() {
return <div class="sample-tutorial">
<div class="sample-container">
<div class="sample-spreadsheets">
<SpreadSheets workbookInitialized={spread => this.initSpread(spread)}>
<Worksheet>
</Worksheet>
</SpreadSheets>
</div>
<div id="statusBar"></div>
</div>
<aside className="options-container" aria-label="SpreadJS file format settings">
<div class="panel-header">
<h1>File Format Settings</h1>
<p class="panel-description">Open and save SpreadJS file or Excel file with format-specific import and export options.</p>
</div>
<div className="option-row">
<section class="inputContainer control-section">
<h2>Open File</h2>
<div class="file-action-row">
<label for="selectedFile">Source File</label>
<input id="selectedFile" type="file" accept=".sjs, .xlsx, .xlsm, .xltm, .xltx, .ssjson, .json, .csv" onChange={this.onSelectedFileChange} />
<button class="settingButton" id="open" onClick={this.open}>Open</button>
</div>
<div class="open-options">
{[
this.createOptions(openOptions, FileType.SJS, 'open'),
this.createOptions(importXlsxOptions, FileType.Excel, 'open'),
this.createOptions(importSSJsonOptions, FileType.SSJson, 'open'),
this.createOptions(importCsvOptions, FileType.Csv, 'open'),
]}
</div>
</section>
<section class="inputContainer control-section">
<h2>Save File</h2>
<div class="save-action-row">
<label for="saveFileType">File Type</label>
<select id="saveFileType" value={this.state.saveFileType} onChange={this.onSaveFileTypeChange}>
<option value="sjs">SJS</option>
<option value="xlsx">Excel</option>
<option value="ssjson">SSJSON</option>
<option value="csv">CSV</option>
</select>
<button class="settingButton" id="save" onClick={this.save}>Save</button>
</div>
{
this.state.saveFileType === FileType.Excel && <div class="excelFileTypeContainer">
<label for="saveExcelFileType">Excel File Type</label>
<div>
<select id="saveExcelFileType" value={this.state.excelFileType} onChange={this.onExcelFileTypeChange}>
<option value="XLSX">Workbook (*.xlsx)</option>
<option value="XLSM">Macro-Enabled Workbook (*.xlsm)</option>
<option value="XLTM">Macro-Enabled Template (*.xltm)</option>
<option value="XLTX">Workbook Template (*.xltx)</option>
</select>
</div>
</div>
}
<div class="save-options">
{[
this.createOptions(saveOptions, FileType.SJS, 'save'),
this.createOptions(exportXlsxOptions, FileType.Excel, 'save'),
this.createOptions(exportSSJsonOptions, FileType.SSJson, 'save'),
this.createOptions(exportCsvOptions, FileType.Csv, 'save'),
]}
</div>
</section>
</div>
</aside>
</div>;
}
initSpread(spread) {
this.spread = spread;
//init Status Bar
var statusBar = new GC.Spread.Sheets.StatusBar.StatusBar(document.getElementById('statusBar'));
statusBar.bind(spread);
}
open() {
var file = this.state.selectedFile;
if (!file) {
return;
}
var fileType = getFileType(file);
var options = deepClone(this.state.openOptions[fileType]);
if (fileType === FileType.SJS) {
this.spread.open(file, function() {}, function() {}, options);
} else {
this.spread.import(file, function() {}, function() {}, options);
}
}
save() {
var fileType = this.state.saveFileType;
var fileName = 'export.' + (fileType === FileType.Excel ? this.state.excelFileType.toLowerCase() : fileType);
var options = deepClone(this.state.saveOptions[fileType]);
if (fileType === FileType.SJS) {
this.spread.save(function(blob) { saveAs(blob, fileName); }, function() {}, options);
} else {
if (fileType === FileType.Csv) {
var { sheetIndex, row, rowCount, column, columnCount } = options;
options.range = {
sheetIndex: sheetIndex,
row: row,
rowCount: rowCount,
column: column,
columnCount: columnCount,
};
}
options.fileType = mapExportFileType(fileType);
this.spread.export(function(blob) { saveAs(blob, fileName); }, function() {}, options);
}
}
onSelectedFileChange(e) {
let selectedFile = e.target.files[0];
let openFileType = getFileType(selectedFile);
this.setState({ ...this.state, selectedFile, openFileType });
}
onSaveFileTypeChange(e) {
let saveFileType = e.target.value;
this.setState({ ...this.state, saveFileType });
}
onExcelFileTypeChange (e) {
const excelFileType = e.target.value;
let saveOptions = deepClone(this.state.saveOptions);
saveOptions.xlsx['excelFileType'] = excelFileType;
this.setState({ ...this.state, excelFileType, saveOptions});
}
onPropChange (mode, fileType, prop, e) {
let element = e.target;
var value;
if (prop.type === 'boolean') {
value = element.checked;
} else if (prop.type === 'number') {
value = +element.value;
} else if (prop.type === 'string') {
value = element.value;
} else if (prop.type === 'select') {
value = +element.value;
}
if (mode === 'open') {
let openOptions = deepClone(this.state.openOptions);
openOptions[fileType][prop.propName] = value;
this.setState({...this.state, openOptions});
} else if (mode === 'save') {
let saveOptions = deepClone(this.state.saveOptions);
saveOptions[fileType][prop.propName] = value;
this.setState({...this.state, saveOptions});
}
}
createOptions (options, fileType, mode) {
let selectFileType = mode === 'open' ? this.state.openFileType : this.state.saveFileType;
let display = selectFileType === fileType ? '' : 'none';
return <div className={fileType} style={{display}}>
{ options.map((prop) => this.createProp(mode, fileType, prop)) }
</div>;
}
createProp (mode, fileType, prop) {
let id = getElementId(mode, fileType, prop.propName);
if (prop.type === 'select') {
return <item className='item'>
<label for={id}>{formatOptionLabel(prop.displayText || prop.propName)}</label>
<select id={id} defaultValue={prop.default} onChange={(e) => this.onPropChange(mode, fileType, prop, e)}>
{ prop.options.map((p) => <option value={p.value}>{p.name}</option>) }
</select>
</item>
} else if (prop.type === 'boolean') {
return <item className='item'>
<input id={id} type='checkbox' defaultChecked={prop.default} onChange={(e) => this.onPropChange(mode, fileType, prop, e)}></input>
<label for={id}>{formatOptionLabel(prop.displayText || prop.propName)}</label>
</item>
} else if (prop.type === 'number') {
return <item className='item'>
<label for={id}>{formatOptionLabel(prop.displayText || prop.propName)}</label>
<input id={id} type='number' defaultValue={prop.default} onChange={(e) => this.onPropChange(mode, fileType, prop, e)}></input>
</item>
} else {
return <item className='item'>
<label for={id}>{formatOptionLabel(prop.displayText || prop.propName)}</label>
<input id={id} type='text' defaultValue={prop.default} onChange={(e) => this.onPropChange(mode, fileType, prop, e)}></input>
</item>
}
}
}
createRoot(document.getElementById('app')).render(<App />);
<!doctype html>
<html style="height:100%;font-size:14px;">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" href="$DEMOROOT$/en/react/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css">
<script src="$DEMOROOT$/spread/source/js/FileSaver.js" type="text/javascript"></script>
<!-- SystemJS -->
<script src="$DEMOROOT$/en/react/node_modules/systemjs/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('$DEMOROOT$/en/lib/react/license.js').then(function () {
System.import('./src/app');
});
</script>
</head>
<body>
<div id="app"></div>
</body>
</html>
html,
body {
height: 100%;
margin: 0;
}
body {
position: absolute;
inset: 0;
color: #1f2933;
background: #f7f8fa;
}
#app {
height: 100%;
}
.sample-tutorial {
display: flex;
height: 100%;
overflow: hidden;
}
.sample-container {
display: flex;
flex: 1 1 auto;
flex-direction: column;
min-width: 0;
height: 100%;
}
.sample-spreadsheets {
flex: 1 1 auto;
min-height: 0;
overflow: hidden;
}
#statusBar {
flex: 0 0 25px;
width: 100%;
}
.options-container {
flex: 0 0 320px;
width: 320px;
height: 100%;
padding: 18px 16px;
box-sizing: border-box;
overflow: auto;
overflow-x: hidden;
background: #ffffff;
border-left: 1px solid #e5e7eb;
}
.sample-options {
z-index: 1000;
}
.panel-header {
padding-bottom: 14px;
border-bottom: 1px solid #eef0f3;
}
.panel-header h1 {
margin: 0;
font-size: 18px;
font-weight: 650;
line-height: 1.25;
}
.panel-description {
margin: 8px 0 0;
color: #6b7280;
font-size: 13px;
line-height: 1.6;
}
.option-row {
display: grid;
}
.inputContainer {
box-sizing: border-box;
}
.control-section {
padding: 14px 0;
border-bottom: 1px solid #eef0f3;
}
.control-section:last-child {
border-bottom: 0;
}
.control-section h2 {
margin: 0 0 10px;
color: #374151;
font-size: 13px;
font-weight: 700;
line-height: 1.3;
}
.options-container label {
color: #374151;
font-size: 13px;
font-weight: 600;
line-height: 1.35;
}
.options-container select,
.options-container input[type="text"],
.options-container input[type="number"] {
width: 100%;
height: 30px;
padding: 0 8px;
box-sizing: border-box;
color: #111827;
font: inherit;
background: #ffffff;
border: 1px solid #d8dde5;
border-radius: 6px;
outline: none;
transition: border-color .15s ease, box-shadow .15s ease;
}
.options-container select:focus,
.options-container input[type="text"]:focus,
.options-container input[type="number"]:focus,
.options-container input[type="file"]:focus,
.options-container button:focus {
border-color: #2563eb;
box-shadow: 0 0 0 3px rgba(37, 99, 235, .12);
}
.options-container input[type="file"] {
display: block;
min-width: 0;
color: #374151;
font-size: 12px;
}
.options-container input[type="file"]::file-selector-button {
height: 28px;
margin-right: 8px;
padding: 0 10px;
color: #1f4f82;
font: inherit;
font-weight: 600;
cursor: pointer;
background: #ffffff;
border: 1px solid #9bb2cf;
border-radius: 4px;
}
.options-container button,
.options-container input[type="button"] {
min-height: 30px;
padding: 0 12px;
box-sizing: border-box;
color: #1f4f82;
font: inherit;
font-weight: 600;
cursor: pointer;
background: #ffffff;
border: 1px solid #9bb2cf;
border-radius: 4px;
transition: background-color .15s ease, border-color .15s ease;
}
.options-container button:hover,
.options-container input[type="button"]:hover {
background: #edf5ff;
border-color: #6f98c8;
}
.settingButton {
flex: 0 0 auto;
margin: 0;
}
.file-action-row,
.save-action-row {
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto;
gap: 8px;
align-items: center;
min-width: 0;
}
.file-action-row {
margin-bottom: 8px;
}
.file-action-row label,
.save-action-row label {
white-space: nowrap;
}
.file-action-row input[type="file"] {
width: 100%;
max-width: 100%;
min-width: 0;
overflow: hidden;
text-overflow: clip;
}
.save-action-row {
margin-bottom: 10px;
}
.save-action-row select {
width: 100%;
min-width: 0;
}
#open,
#save {
min-width: 56px;
}
.open-options .item,
.save-options .item {
display: flex;
gap: 8px;
align-items: center;
min-height: 24px;
margin: 4px 0;
}
.open-options .item label,
.save-options .item label {
flex: 1 1 auto;
min-width: 0;
font-weight: 500;
overflow-wrap: anywhere;
}
.open-options .item select,
.save-options .item select,
.open-options .item input[type="text"],
.save-options .item input[type="text"],
.open-options .item input[type="number"],
.save-options .item input[type="number"] {
flex: 0 0 128px;
width: 128px;
height: 28px;
}
.open-options .item input[type="checkbox"],
.save-options .item input[type="checkbox"] {
width: 16px;
height: 16px;
margin: 0;
accent-color: #2563eb;
flex: 0 0 auto;
}
.excelFileTypeContainer {
margin-bottom: 10px;
}
#saveExcelFileType {
margin: 8px 0 0;
}
@media (max-width: 760px) {
.sample-tutorial {
flex-direction: column;
}
.sample-container {
flex: 1 1 55%;
min-height: 55%;
}
.options-container {
flex: 0 0 45%;
width: 100%;
height: 45%;
border-top: 1px solid #e5e7eb;
border-left: 0;
}
}
(function (global) {
System.config({
transpiler: 'plugin-babel',
babelOptions: {
es2015: true,
react: true
},
meta: {
'*.css': { loader: 'css' }
},
paths: {
// paths serve as alias
'npm:': 'node_modules/',
'cdn:': 'https://cdn.mescius.io/demoapps/packages/spreadjs/19.2.0-master-2026-08-10-0936/'
},
// map tells the System loader where to look for things
map: {
'@mescius/spread-sheets': 'cdn:@mescius/spread-sheets/index.js',
'@mescius/spread-sheets-print': 'cdn:@mescius/spread-sheets-print/index.js',
'@mescius/spread-sheets-react': 'cdn:@mescius/spread-sheets-react/index.js',
'@mescius/spread-sheets-io': 'cdn:@mescius/spread-sheets-io/index.js',
'@mescius/spread-sheets-charts': 'cdn:@mescius/spread-sheets-charts/index.js',
'@mescius/spread-sheets-shapes': 'cdn:@mescius/spread-sheets-shapes/index.js',
'@mescius/spread-sheets-slicers': 'cdn:@mescius/spread-sheets-slicers/index.js',
'@mescius/spread-sheets-pivot-addon': 'cdn:@mescius/spread-sheets-pivot-addon/index.js',
'@mescius/spread-sheets-reportsheet-addon': 'cdn:@mescius/spread-sheets-reportsheet-addon/index.js',
'@mescius/spread-sheets-tablesheet': 'cdn:@mescius/spread-sheets-tablesheet/index.js',
'@mescius/spread-sheets-ganttsheet': 'cdn:@mescius/spread-sheets-ganttsheet/index.js',
'@grapecity/jsob-test-dependency-package/react-components': 'npm:@grapecity/jsob-test-dependency-package/react-components/index.js',
'react': 'npm:react/cjs/react.production.js',
'react-dom': 'npm:react-dom/cjs/react-dom.production.js',
'react-dom/client': 'npm:react-dom/cjs/react-dom-client.production.js',
'scheduler': 'npm:scheduler/cjs/scheduler.production.js',
'css': 'npm:systemjs-plugin-css/css.js',
'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js',
'systemjs-babel-build':'npm:systemjs-plugin-babel/systemjs-babel-browser.js'
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
src: {
defaultExtension: 'jsx'
},
"node_modules": {
defaultExtension: 'js'
},
}
});
})(this);