mirror of
https://github.com/ruilisi/fortune-sheet.git
synced 2025-01-07 03:16:50 +08:00
feat: init apis
This commit is contained in:
parent
a81ab9d3e1
commit
9e708fcf90
@ -9,7 +9,7 @@ export const parameters = {
|
||||
options: {
|
||||
storySort: {
|
||||
// put Workbook at first
|
||||
order: ['Workbook'],
|
||||
order: ["Features", "API"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
281
packages/core/src/api/cell.ts
Normal file
281
packages/core/src/api/cell.ts
Normal file
@ -0,0 +1,281 @@
|
||||
import _ from "lodash";
|
||||
import { Context, getFlowdata } from "../context";
|
||||
import {
|
||||
delFunctionGroup,
|
||||
functionHTMLGenerate,
|
||||
setCellValue as setCellValueInternal,
|
||||
updateCell,
|
||||
updateFormatCell,
|
||||
} from "../modules";
|
||||
import { Cell, CellStyle } from "../types";
|
||||
import { CommonOptions, getSheet } from "./common";
|
||||
import { SHEET_NOT_FOUND } from "./errors";
|
||||
|
||||
export function getCellValue(
|
||||
ctx: Context,
|
||||
row: number,
|
||||
column: number,
|
||||
options: CommonOptions & { type?: keyof Cell } = {}
|
||||
) {
|
||||
if (!_.isNumber(row) || !_.isNumber(column)) {
|
||||
throw new Error("row or column cannot be null or undefined");
|
||||
}
|
||||
const sheet = getSheet(ctx, options);
|
||||
const { type = "v" } = options;
|
||||
const targetSheetData = sheet.data;
|
||||
if (!targetSheetData) {
|
||||
throw SHEET_NOT_FOUND;
|
||||
}
|
||||
const cellData = targetSheetData[row][column];
|
||||
let ret;
|
||||
|
||||
if (cellData && _.isPlainObject(cellData)) {
|
||||
ret = cellData[type];
|
||||
|
||||
if (type === "f" && ret != null) {
|
||||
ret = functionHTMLGenerate(ret);
|
||||
} else if (type === "f") {
|
||||
ret = cellData.v;
|
||||
} else if (cellData && cellData.ct && cellData.ct.fa === "yyyy-MM-dd") {
|
||||
ret = cellData.m;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret === undefined) {
|
||||
ret = null;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
export function setCellValue(
|
||||
ctx: Context,
|
||||
row: number,
|
||||
column: number,
|
||||
value: any,
|
||||
cellInput: HTMLDivElement,
|
||||
options: CommonOptions = {}
|
||||
) {
|
||||
const flowdata = getFlowdata(ctx);
|
||||
if (!flowdata) return;
|
||||
|
||||
// const curv = flowdata[row][column];
|
||||
|
||||
// // Store old value for hook function
|
||||
// const oldValue = JSON.stringify(curv);
|
||||
|
||||
if (!_.isNumber(row) || !_.isNumber(column)) {
|
||||
throw new Error("row or column cannot be null or undefined");
|
||||
}
|
||||
|
||||
const sheet = getSheet(ctx, options);
|
||||
|
||||
// /* cell更新前触发 */
|
||||
// if (
|
||||
// !method.createHookFunction(
|
||||
// "cellUpdateBefore",
|
||||
// row,
|
||||
// column,
|
||||
// value,
|
||||
// isRefresh
|
||||
// )
|
||||
// ) {
|
||||
// /* 如果cellUpdateBefore函数返回false 则不执行后续的更新 */
|
||||
// return;
|
||||
// }
|
||||
|
||||
const { data } = sheet;
|
||||
// if (data.length === 0) {
|
||||
// data = sheetmanage.buildGridData(file);
|
||||
// }
|
||||
|
||||
// luckysheetformula.updatecell(row, column, value);
|
||||
const formatList = {
|
||||
// ct:1, //celltype,Cell value format: text, time, etc.
|
||||
bg: 1, // background,#fff000
|
||||
ff: 1, // fontfamily,
|
||||
fc: 1, // fontcolor
|
||||
bl: 1, // Bold
|
||||
it: 1, // italic
|
||||
fs: 1, // font size
|
||||
cl: 1, // Cancelline, 0 Regular, 1 Cancelline
|
||||
un: 1, // underline, 0 Regular, 1 underlines, fonts
|
||||
vt: 1, // Vertical alignment, 0 middle, 1 up, 2 down
|
||||
ht: 1, // Horizontal alignment,0 center, 1 left, 2 right
|
||||
mc: 1, // Merge Cells
|
||||
tr: 1, // Text rotation,0: 0、1: 45 、2: -45、3 Vertical text、4: 90 、5: -90
|
||||
tb: 1, // Text wrap,0 truncation, 1 overflow, 2 word wrap
|
||||
// v: 1, //Original value
|
||||
// m: 1, //Display value
|
||||
rt: 1, // text rotation angle 0-180 alignment
|
||||
// f: 1, //formula
|
||||
qp: 1, // quotePrefix, show number as string
|
||||
};
|
||||
|
||||
if (value == null || value.toString().length === 0) {
|
||||
delFunctionGroup(ctx, row, column);
|
||||
setCellValueInternal(ctx, row, column, data, value);
|
||||
} else if (value instanceof Object) {
|
||||
const curv: Cell = {};
|
||||
if (data?.[row]?.[column] == null) {
|
||||
data![row][column] = {};
|
||||
}
|
||||
const cell = data![row][column]!;
|
||||
if (value.f != null && value.v == null) {
|
||||
curv.f = value.f;
|
||||
if (value.ct != null) {
|
||||
curv.ct = value.ct;
|
||||
}
|
||||
updateCell(ctx, row, column, cellInput, curv); // update formula value
|
||||
} else {
|
||||
if (value.ct != null) {
|
||||
curv.ct = value.ct;
|
||||
}
|
||||
if (value.f != null) {
|
||||
curv.f = value.f;
|
||||
}
|
||||
if (value.v != null) {
|
||||
curv.v = value.v;
|
||||
} else {
|
||||
curv.v = cell.v;
|
||||
}
|
||||
if (value.m != null) {
|
||||
curv.m = value.m;
|
||||
}
|
||||
delFunctionGroup(ctx, row, column);
|
||||
setCellValueInternal(ctx, row, column, data, curv); // update text value
|
||||
}
|
||||
_.forEach(value, (v, attr) => {
|
||||
if (attr in formatList) {
|
||||
updateFormatCell(
|
||||
ctx,
|
||||
data!,
|
||||
attr as keyof CellStyle,
|
||||
v,
|
||||
row,
|
||||
row,
|
||||
column,
|
||||
column
|
||||
); // change range format
|
||||
} else {
|
||||
// @ts-ignore
|
||||
cell[attr] = v;
|
||||
}
|
||||
});
|
||||
data![row][column] = cell;
|
||||
} else {
|
||||
if (
|
||||
value.toString().substr(0, 1) === "=" ||
|
||||
value.toString().substr(0, 5) === "<span"
|
||||
) {
|
||||
updateCell(ctx, row, column, cellInput, value); // update formula value or convert inline string html to object
|
||||
} else {
|
||||
delFunctionGroup(ctx, row, column);
|
||||
setCellValueInternal(ctx, row, column, data, value);
|
||||
}
|
||||
}
|
||||
|
||||
// /* cell更新后触发 */
|
||||
// setTimeout(() => {
|
||||
// // Hook function
|
||||
// method.createHookFunction(
|
||||
// "cellUpdated",
|
||||
// row,
|
||||
// column,
|
||||
// JSON.parse(oldValue),
|
||||
// ctx.flowdata[row][column],
|
||||
// isRefresh
|
||||
// );
|
||||
// }, 0);
|
||||
}
|
||||
|
||||
export function clearCell(
|
||||
ctx: Context,
|
||||
row: number,
|
||||
column: number,
|
||||
options: CommonOptions = {}
|
||||
) {
|
||||
if (!_.isNumber(row) || !_.isNumber(column)) {
|
||||
throw new Error("row or column cannot be null or undefined");
|
||||
}
|
||||
|
||||
const sheet = getSheet(ctx, options);
|
||||
|
||||
const cell = sheet.data?.[row]?.[column];
|
||||
|
||||
if (cell && _.isPlainObject(cell)) {
|
||||
delete cell.m;
|
||||
delete cell.v;
|
||||
|
||||
if (cell.f != null) {
|
||||
delete cell.f;
|
||||
delFunctionGroup(ctx, row, column, sheet.index);
|
||||
|
||||
delete cell.spl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function setCellFormat(
|
||||
ctx: Context,
|
||||
row: number,
|
||||
column: number,
|
||||
attr: keyof Cell,
|
||||
value: any,
|
||||
options: CommonOptions = {}
|
||||
) {
|
||||
if (!_.isNumber(row) || !_.isNumber(column)) {
|
||||
throw new Error("row or column cannot be null or undefined");
|
||||
}
|
||||
|
||||
if (!attr) {
|
||||
throw new Error("attr cannot be null or undefined");
|
||||
}
|
||||
|
||||
const sheet = getSheet(ctx, options);
|
||||
|
||||
const targetSheetData = sheet.data!;
|
||||
// if (targetSheetData.length === 0) {
|
||||
// targetSheetData = sheetmanage.buildGridData(sheet);
|
||||
// }
|
||||
|
||||
const cellData = targetSheetData?.[row]?.[column] || {};
|
||||
const cfg = sheet.config || {};
|
||||
|
||||
// 特殊格式
|
||||
if (attr === "ct" && (!value || value.fa == null || value.t == null)) {
|
||||
throw new Error(
|
||||
"'fa' and 't' should be present in value when attr is 'ct'"
|
||||
);
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
if (attr === "bd") {
|
||||
if (cfg.borderInfo == null) {
|
||||
cfg.borderInfo = [];
|
||||
}
|
||||
|
||||
const borderInfo = {
|
||||
rangeType: "range",
|
||||
borderType: "border-all",
|
||||
color: "#000",
|
||||
style: "1",
|
||||
range: [
|
||||
{
|
||||
column: [column, column],
|
||||
row: [row, row],
|
||||
},
|
||||
],
|
||||
...value,
|
||||
};
|
||||
|
||||
cfg.borderInfo.push(borderInfo);
|
||||
} else {
|
||||
cellData[attr] = value;
|
||||
}
|
||||
|
||||
targetSheetData[row][column] = cellData;
|
||||
|
||||
sheet.config = cfg;
|
||||
ctx.config = cfg;
|
||||
}
|
21
packages/core/src/api/common.ts
Normal file
21
packages/core/src/api/common.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { Context } from "../context";
|
||||
import { getSheetIndex } from "../utils";
|
||||
import { SHEET_NOT_FOUND } from "./errors";
|
||||
|
||||
export type CommonOptions = { order?: number };
|
||||
|
||||
export function getSheet(ctx: Context, options: CommonOptions = {}) {
|
||||
const { order = getSheetIndex(ctx, ctx.currentSheetIndex) } = options;
|
||||
|
||||
if (order == null) {
|
||||
throw SHEET_NOT_FOUND;
|
||||
}
|
||||
|
||||
const sheet = ctx.luckysheetfile[order];
|
||||
|
||||
if (sheet == null) {
|
||||
throw SHEET_NOT_FOUND;
|
||||
}
|
||||
|
||||
return sheet;
|
||||
}
|
2
packages/core/src/api/errors.ts
Normal file
2
packages/core/src/api/errors.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export const INVALID_PARAMS = new Error("invalid params");
|
||||
export const SHEET_NOT_FOUND = new Error("sheet not found");
|
5
packages/core/src/api/index.ts
Normal file
5
packages/core/src/api/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import type { CommonOptions } from "./common";
|
||||
|
||||
export type { CommonOptions };
|
||||
export * from "./cell";
|
||||
export * from "./rowcol";
|
206
packages/core/src/api/rowcol.ts
Normal file
206
packages/core/src/api/rowcol.ts
Normal file
@ -0,0 +1,206 @@
|
||||
import _ from "lodash";
|
||||
import { Context } from "../context";
|
||||
import { deleteRowCol, insertRowCol } from "../modules";
|
||||
import { CommonOptions, getSheet } from "./common";
|
||||
import { INVALID_PARAMS } from "./errors";
|
||||
|
||||
export function freeze(
|
||||
ctx: Context,
|
||||
type: "row" | "column" | "both",
|
||||
range: { row: number; column: number },
|
||||
options: CommonOptions = {}
|
||||
) {
|
||||
const sheet = getSheet(ctx, options);
|
||||
|
||||
const typeMap = {
|
||||
row: "rangeRow",
|
||||
column: "rangeColumn",
|
||||
both: "rangeBoth",
|
||||
};
|
||||
const innerType = typeMap[type];
|
||||
|
||||
sheet.frozen = {
|
||||
// @ts-ignore
|
||||
type: innerType,
|
||||
range: {
|
||||
column_focus: range.column,
|
||||
row_focus: range.row,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function insertRowOrColumn(
|
||||
ctx: Context,
|
||||
type: "row" | "column",
|
||||
index: number,
|
||||
count: number,
|
||||
direction: "lefttop" | "rightbottom",
|
||||
options: CommonOptions = {}
|
||||
) {
|
||||
if (
|
||||
!["row", "column"].includes(type) ||
|
||||
!_.isNumber(index) ||
|
||||
!_.isNumber(count) ||
|
||||
!["lefttop", "rightbottom"].includes(direction)
|
||||
) {
|
||||
throw INVALID_PARAMS;
|
||||
}
|
||||
|
||||
const sheet = getSheet(ctx, options);
|
||||
|
||||
insertRowCol(ctx, {
|
||||
type,
|
||||
index,
|
||||
count,
|
||||
direction,
|
||||
sheetIndex: sheet.index!,
|
||||
});
|
||||
}
|
||||
|
||||
export function deleteRowOrColumn(
|
||||
ctx: Context,
|
||||
type: "row" | "column",
|
||||
start: number,
|
||||
end: number,
|
||||
options: CommonOptions = {}
|
||||
) {
|
||||
if (
|
||||
!["row", "column"].includes(type) ||
|
||||
!_.isNumber(start) ||
|
||||
!_.isNumber(end)
|
||||
) {
|
||||
throw INVALID_PARAMS;
|
||||
}
|
||||
|
||||
const sheet = getSheet(ctx, options);
|
||||
|
||||
deleteRowCol(ctx, { type, start, end, sheetIndex: sheet.index! });
|
||||
}
|
||||
|
||||
export function setRowHeight(
|
||||
ctx: Context,
|
||||
rowInfo: Record<string, number>,
|
||||
options: CommonOptions = {}
|
||||
) {
|
||||
if (!_.isPlainObject(rowInfo)) {
|
||||
throw INVALID_PARAMS;
|
||||
}
|
||||
|
||||
const sheet = getSheet(ctx, options);
|
||||
|
||||
const cfg = sheet.config || {};
|
||||
if (cfg.rowlen == null) {
|
||||
cfg.rowlen = {};
|
||||
}
|
||||
|
||||
_.forEach(rowInfo, (len, r) => {
|
||||
if (Number(r) >= 0) {
|
||||
if (Number(len) >= 0) {
|
||||
cfg.rowlen![Number(r)] = Number(len);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
sheet.config = cfg;
|
||||
|
||||
// server.saveParam("cg", file.index, cfg.rowlen, { k: "rowlen" });
|
||||
|
||||
// if (file.index === ctx.currentSheetIndex) {
|
||||
// ctx.config = cfg;
|
||||
// jfrefreshgrid_rhcw(ctx.flowdata.length, ctx.flowdata[0].length);
|
||||
// }
|
||||
|
||||
// if (success && typeof success === "function") {
|
||||
// success();
|
||||
// }
|
||||
}
|
||||
|
||||
export function setColumnWidth(
|
||||
ctx: Context,
|
||||
columnInfo: Record<string, number>,
|
||||
options: CommonOptions = {}
|
||||
) {
|
||||
if (!_.isPlainObject(columnInfo)) {
|
||||
throw INVALID_PARAMS;
|
||||
}
|
||||
|
||||
const sheet = getSheet(ctx, options);
|
||||
|
||||
const cfg = sheet.config || {};
|
||||
if (cfg.columnlen == null) {
|
||||
cfg.columnlen = {};
|
||||
}
|
||||
|
||||
_.forEach(columnInfo, (len, c) => {
|
||||
if (Number(c) >= 0) {
|
||||
if (Number(len) >= 0) {
|
||||
cfg.columnlen![Number(c)] = Number(len);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
sheet.config = cfg;
|
||||
|
||||
// server.saveParam("cg", file.index, cfg.columnlen, { k: "columnlen" });
|
||||
|
||||
// if (file.index === ctx.currentSheetIndex) {
|
||||
// ctx.config = cfg;
|
||||
// jfrefreshgrid_rhcw(ctx.flowdata.length, ctx.flowdata[0].length);
|
||||
// }
|
||||
|
||||
// if (success && typeof success === "function") {
|
||||
// success();
|
||||
// }
|
||||
}
|
||||
|
||||
export function getRowHeight(
|
||||
ctx: Context,
|
||||
rows: number[],
|
||||
options: CommonOptions = {}
|
||||
) {
|
||||
if (!_.isArray(rows) || rows.length === 0) {
|
||||
throw INVALID_PARAMS;
|
||||
}
|
||||
|
||||
const sheet = getSheet(ctx, options);
|
||||
|
||||
const cfg = sheet.config || {};
|
||||
const rowlen = cfg.rowlen || {};
|
||||
|
||||
const rowlenObj: Record<number, number> = {};
|
||||
|
||||
rows.forEach((item) => {
|
||||
if (Number(item) >= 0) {
|
||||
const size = rowlen[Number(item)] || ctx.defaultrowlen;
|
||||
rowlenObj[Number(item)] = size;
|
||||
}
|
||||
});
|
||||
|
||||
return rowlenObj;
|
||||
}
|
||||
|
||||
export function getColumnWidth(
|
||||
ctx: Context,
|
||||
columns: number[],
|
||||
options: CommonOptions = {}
|
||||
) {
|
||||
if (!_.isArray(columns) || columns.length === 0) {
|
||||
throw INVALID_PARAMS;
|
||||
}
|
||||
|
||||
const sheet = getSheet(ctx, options);
|
||||
|
||||
const cfg = sheet.config || {};
|
||||
const columnlen = cfg.columnlen || {};
|
||||
|
||||
const columnlenObj: Record<number, number> = {};
|
||||
|
||||
columns.forEach((item) => {
|
||||
if (Number(item) >= 0) {
|
||||
const size = columnlen[Number(item)] || ctx.defaultcollen;
|
||||
columnlenObj[Number(item)] = size;
|
||||
}
|
||||
});
|
||||
|
||||
return columnlenObj;
|
||||
}
|
@ -1,3 +1,7 @@
|
||||
import * as api from "./api";
|
||||
|
||||
export { api };
|
||||
|
||||
export * from "./canvas";
|
||||
export * from "./context";
|
||||
export * from "./settings";
|
||||
|
@ -655,11 +655,11 @@ export function updateCell(
|
||||
ctx: Context,
|
||||
r: number,
|
||||
c: number,
|
||||
$input: HTMLDivElement,
|
||||
$input?: HTMLDivElement,
|
||||
value?: any
|
||||
) {
|
||||
let inputText = $input.innerText;
|
||||
const inputHtml = $input.innerHTML;
|
||||
let inputText = $input?.innerText;
|
||||
const inputHtml = $input?.innerHTML;
|
||||
const flowdata = getFlowdata(ctx);
|
||||
if (!flowdata) return;
|
||||
|
||||
@ -696,7 +696,7 @@ export function updateCell(
|
||||
|
||||
const isPrevInline = isInlineStringCell(curv);
|
||||
let isCurInline =
|
||||
inputText.slice(0, 1) !== "=" && inputHtml.substring(0, 5) === "<span";
|
||||
inputText?.slice(0, 1) !== "=" && inputHtml?.substring(0, 5) === "<span";
|
||||
|
||||
let isCopyVal = false;
|
||||
if (!isCurInline && inputText && inputText.length > 0) {
|
||||
@ -733,7 +733,7 @@ export function updateCell(
|
||||
}
|
||||
|
||||
curv.ct.t = "inlineStr";
|
||||
curv.ct.s = convertSpanToShareString($input.querySelectorAll("span"));
|
||||
curv.ct.s = convertSpanToShareString($input!.querySelectorAll("span"));
|
||||
if (isCopyVal) {
|
||||
curv.ct.s = [
|
||||
{
|
||||
@ -744,7 +744,7 @@ export function updateCell(
|
||||
}
|
||||
|
||||
// API, we get value from user
|
||||
value = value || $input.innerText;
|
||||
value = value || $input?.innerText;
|
||||
|
||||
// Hook function
|
||||
// if (!method.createHookFunction("cellUpdateBefore", r, c, value, isRefresh)) {
|
||||
|
@ -41,7 +41,7 @@ type ToolbarItemClickHandler = (
|
||||
|
||||
type ToolbarItemSelectedFunc = (cell: Cell | null | undefined) => boolean;
|
||||
|
||||
function updateFormatCell(
|
||||
export function updateFormatCell(
|
||||
ctx: Context,
|
||||
d: CellMatrix,
|
||||
attr: keyof Cell,
|
||||
|
128
packages/react/src/components/Workbook/api.ts
Normal file
128
packages/react/src/components/Workbook/api.ts
Normal file
@ -0,0 +1,128 @@
|
||||
import {
|
||||
addSheet,
|
||||
api,
|
||||
Cell,
|
||||
Context,
|
||||
deleteRowCol,
|
||||
deleteSheet,
|
||||
insertRowCol,
|
||||
Op,
|
||||
opToPatch,
|
||||
} from "@fortune-sheet/core";
|
||||
import produce, { applyPatches } from "immer";
|
||||
import { SetContextOptions } from "../../context";
|
||||
|
||||
export function generateAPIs(
|
||||
context: Context,
|
||||
setContext: (
|
||||
recipe: (ctx: Context) => void,
|
||||
options?: SetContextOptions
|
||||
) => void,
|
||||
cellInput: HTMLDivElement | null
|
||||
) {
|
||||
return {
|
||||
applyOp: (ops: Op[]) => {
|
||||
setContext((ctx_) => {
|
||||
const [patches, specialOps] = opToPatch(ctx_, ops);
|
||||
if (specialOps.length > 0) {
|
||||
const [specialOp] = specialOps;
|
||||
if (specialOp.op === "insertRowCol") {
|
||||
ctx_ = produce(ctx_, (draftCtx) => {
|
||||
insertRowCol(draftCtx, specialOp.value);
|
||||
});
|
||||
} else if (specialOp.op === "deleteRowCol") {
|
||||
ctx_ = produce(ctx_, (draftCtx) => {
|
||||
deleteRowCol(draftCtx, specialOp.value);
|
||||
});
|
||||
} else if (specialOp.op === "addSheet") {
|
||||
ctx_ = produce(ctx_, (draftCtx) => {
|
||||
addSheet(draftCtx);
|
||||
});
|
||||
} else if (specialOp.op === "deleteSheet") {
|
||||
ctx_ = produce(ctx_, (draftCtx) => {
|
||||
deleteSheet(draftCtx, specialOp.value.index);
|
||||
});
|
||||
}
|
||||
}
|
||||
const newContext = applyPatches(ctx_, patches);
|
||||
return newContext;
|
||||
});
|
||||
},
|
||||
|
||||
getCellValue: (
|
||||
row: number,
|
||||
column: number,
|
||||
options: { type?: keyof Cell; order?: number } = {}
|
||||
) => api.getCellValue(context, row, column, options),
|
||||
|
||||
setCellValue: (
|
||||
row: number,
|
||||
column: number,
|
||||
value: any,
|
||||
options: { type?: keyof Cell; order?: number } = {}
|
||||
) =>
|
||||
setContext((draftCtx) =>
|
||||
api.setCellValue(draftCtx, row, column, value, cellInput!, options)
|
||||
),
|
||||
|
||||
clearCell: (row: number, column: number, options: api.CommonOptions = {}) =>
|
||||
setContext((draftCtx) => api.clearCell(draftCtx, row, column, options)),
|
||||
|
||||
setCellFormat: (
|
||||
row: number,
|
||||
column: number,
|
||||
attr: keyof Cell,
|
||||
value: any,
|
||||
options: api.CommonOptions = {}
|
||||
) =>
|
||||
setContext((draftCtx) =>
|
||||
api.setCellFormat(draftCtx, row, column, attr, value, options)
|
||||
),
|
||||
|
||||
freeze: (
|
||||
type: "row" | "column" | "both",
|
||||
range: { row: number; column: number },
|
||||
options: api.CommonOptions = {}
|
||||
) => setContext((draftCtx) => api.freeze(draftCtx, type, range, options)),
|
||||
|
||||
insertRowOrColumn: (
|
||||
type: "row" | "column",
|
||||
index: number,
|
||||
count: number,
|
||||
direction: "lefttop" | "rightbottom" = "rightbottom",
|
||||
options: api.CommonOptions = {}
|
||||
) =>
|
||||
setContext((draftCtx) =>
|
||||
api.insertRowOrColumn(draftCtx, type, index, count, direction, options)
|
||||
),
|
||||
|
||||
deleteRowOrColumn: (
|
||||
type: "row" | "column",
|
||||
start: number,
|
||||
end: number,
|
||||
options: api.CommonOptions = {}
|
||||
) =>
|
||||
setContext((draftCtx) =>
|
||||
api.deleteRowOrColumn(draftCtx, type, start, end, options)
|
||||
),
|
||||
|
||||
setRowHeight: (
|
||||
rowInfo: Record<string, number>,
|
||||
options: api.CommonOptions = {}
|
||||
) => setContext((draftCtx) => api.setRowHeight(draftCtx, rowInfo, options)),
|
||||
|
||||
setColumnWidth: (
|
||||
columnInfo: Record<string, number>,
|
||||
options: api.CommonOptions = {}
|
||||
) =>
|
||||
setContext((draftCtx) =>
|
||||
api.setColumnWidth(draftCtx, columnInfo, options)
|
||||
),
|
||||
|
||||
getRowHeight: (rows: number[], options: api.CommonOptions = {}) =>
|
||||
api.getRowHeight(context, rows, options),
|
||||
|
||||
getColumnWidth: (columns: number[], options: api.CommonOptions = {}) =>
|
||||
api.getColumnWidth(context, columns, options),
|
||||
};
|
||||
}
|
@ -13,12 +13,7 @@ import {
|
||||
filterPatch,
|
||||
patchToOp,
|
||||
Op,
|
||||
opToPatch,
|
||||
inverseRowColOptions,
|
||||
insertRowCol,
|
||||
deleteRowCol,
|
||||
addSheet,
|
||||
deleteSheet,
|
||||
ensureSheetIndex,
|
||||
} from "@fortune-sheet/core";
|
||||
import React, {
|
||||
@ -46,12 +41,11 @@ import ContextMenu from "../ContextMenu";
|
||||
import SVGDefines from "../SVGDefines";
|
||||
import SheetTabContextMenu from "../ContextMenu/SheetTab";
|
||||
import MoreItemsContaier from "../Toolbar/MoreItemsContainer";
|
||||
import { generateAPIs } from "./api";
|
||||
|
||||
enablePatches();
|
||||
|
||||
export type WorkbookInstance = {
|
||||
applyOp: (ops: Op[]) => void;
|
||||
};
|
||||
export type WorkbookInstance = ReturnType<typeof generateAPIs>;
|
||||
|
||||
type AdditionalProps = {
|
||||
onChange?: (data: SheetType[]) => void;
|
||||
@ -78,34 +72,6 @@ const Workbook = React.forwardRef<WorkbookInstance, Settings & AdditionalProps>(
|
||||
[..._.values(props)]
|
||||
);
|
||||
|
||||
const applyOp = useCallback((ops: Op[]) => {
|
||||
setContext((ctx_) => {
|
||||
const [patches, specialOps] = opToPatch(ctx_, ops);
|
||||
if (specialOps.length > 0) {
|
||||
const [specialOp] = specialOps;
|
||||
if (specialOp.op === "insertRowCol") {
|
||||
ctx_ = produce(ctx_, (draftCtx) => {
|
||||
insertRowCol(draftCtx, specialOp.value);
|
||||
});
|
||||
} else if (specialOp.op === "deleteRowCol") {
|
||||
ctx_ = produce(ctx_, (draftCtx) => {
|
||||
deleteRowCol(draftCtx, specialOp.value);
|
||||
});
|
||||
} else if (specialOp.op === "addSheet") {
|
||||
ctx_ = produce(ctx_, (draftCtx) => {
|
||||
addSheet(draftCtx);
|
||||
});
|
||||
} else if (specialOp.op === "deleteSheet") {
|
||||
ctx_ = produce(ctx_, (draftCtx) => {
|
||||
deleteSheet(draftCtx, specialOp.value.index);
|
||||
});
|
||||
}
|
||||
}
|
||||
const newContext = applyPatches(ctx_, patches);
|
||||
return newContext;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const emitOp = useCallback(
|
||||
(ctx: Context, patches: Patch[], options?: SetContextOptions) => {
|
||||
if (onOp) {
|
||||
@ -115,8 +81,6 @@ const Workbook = React.forwardRef<WorkbookInstance, Settings & AdditionalProps>(
|
||||
[onOp]
|
||||
);
|
||||
|
||||
useImperativeHandle(ref, () => ({ applyOp }));
|
||||
|
||||
const setContextWithProduce = useCallback(
|
||||
(recipe: (ctx: Context) => void, options: SetContextOptions = {}) => {
|
||||
setContext((ctx_) => {
|
||||
@ -389,6 +353,13 @@ const Workbook = React.forwardRef<WorkbookInstance, Settings & AdditionalProps>(
|
||||
};
|
||||
}, [onPaste]);
|
||||
|
||||
// expose APIs
|
||||
useImperativeHandle(
|
||||
ref,
|
||||
() => generateAPIs(context, setContextWithProduce, cellInput.current),
|
||||
[context, setContextWithProduce]
|
||||
);
|
||||
|
||||
const i = getSheetIndex(context, context.currentSheetIndex);
|
||||
if (i == null) {
|
||||
return null;
|
||||
|
191
stories/API.stories.tsx
Normal file
191
stories/API.stories.tsx
Normal file
@ -0,0 +1,191 @@
|
||||
import React, { useRef, useEffect } from "react";
|
||||
import { ComponentMeta, ComponentStory } from "@storybook/react";
|
||||
import { Workbook, WorkbookInstance } from "@fortune-sheet/react";
|
||||
|
||||
export default {
|
||||
component: Workbook,
|
||||
} as ComponentMeta<typeof Workbook>;
|
||||
|
||||
export const SetCellValue: ComponentStory<typeof Workbook> = () => {
|
||||
const ref = useRef<WorkbookInstance>(null);
|
||||
useEffect(() => {
|
||||
for (let i = 0; i < 5; i += 1) {
|
||||
for (let j = 0; j < 5; j += 1) {
|
||||
ref.current?.setCellValue(i, j, `${i + j}`);
|
||||
}
|
||||
}
|
||||
ref.current?.setCellValue(0, 5, "=SUM(A1:E1)");
|
||||
ref.current?.setCellValue(1, 5, "=SUM(A2:E2)");
|
||||
ref.current?.setCellValue(2, 5, "=SUM(A3:E3)");
|
||||
ref.current?.setCellValue(3, 5, "=SUM(A4:E4)");
|
||||
ref.current?.setCellValue(4, 5, "=SUM(A5:E5)");
|
||||
});
|
||||
return (
|
||||
<div style={{ width: "100%", height: "100%" }}>
|
||||
<Workbook ref={ref} data={[{ name: "Sheet1" }]} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const ClearCell: ComponentStory<typeof Workbook> = () => {
|
||||
const ref = useRef<WorkbookInstance>(null);
|
||||
useEffect(() => {
|
||||
ref.current?.clearCell(0, 0);
|
||||
});
|
||||
return (
|
||||
<div style={{ width: "100%", height: "100%" }}>
|
||||
<Workbook
|
||||
ref={ref}
|
||||
data={[
|
||||
{
|
||||
name: "Sheet1",
|
||||
data: [[{ bg: "green", v: "fortune", m: "fortune" }]],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const SetCellFormat: ComponentStory<typeof Workbook> = () => {
|
||||
const ref = useRef<WorkbookInstance>(null);
|
||||
useEffect(() => {
|
||||
ref.current?.setCellFormat(0, 0, "bg", "green");
|
||||
});
|
||||
return (
|
||||
<div style={{ width: "100%", height: "100%" }}>
|
||||
<Workbook
|
||||
ref={ref}
|
||||
data={[
|
||||
{
|
||||
name: "Sheet1",
|
||||
config: { columnlen: { "0": 120 } },
|
||||
data: [[{ v: "set bg = green" }]],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Freeze: ComponentStory<typeof Workbook> = () => {
|
||||
const ref = useRef<WorkbookInstance>(null);
|
||||
useEffect(() => {
|
||||
ref.current?.freeze("both", { row: 1, column: 1 });
|
||||
});
|
||||
return (
|
||||
<div style={{ width: "100%", height: "100%" }}>
|
||||
<Workbook
|
||||
ref={ref}
|
||||
data={[
|
||||
{
|
||||
name: "Sheet1",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const InsertRowCol: ComponentStory<typeof Workbook> = () => {
|
||||
const ref = useRef<WorkbookInstance>(null);
|
||||
useEffect(() => {
|
||||
ref.current?.insertRowOrColumn("row", 0, 1);
|
||||
ref.current?.setCellValue(1, 0, "inserted");
|
||||
ref.current?.insertRowOrColumn("column", 0, 1);
|
||||
ref.current?.setCellValue(0, 1, "inserted");
|
||||
});
|
||||
return (
|
||||
<div style={{ width: "100%", height: "100%" }}>
|
||||
<Workbook
|
||||
ref={ref}
|
||||
data={[
|
||||
{
|
||||
name: "Sheet1",
|
||||
data: [[{ v: "original" }]],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const DeleteRowCol: ComponentStory<typeof Workbook> = () => {
|
||||
const ref = useRef<WorkbookInstance>(null);
|
||||
useEffect(() => {
|
||||
ref.current?.deleteRowOrColumn("row", 1, 3);
|
||||
});
|
||||
return (
|
||||
<div style={{ width: "100%", height: "100%" }}>
|
||||
<Workbook
|
||||
ref={ref}
|
||||
data={[
|
||||
{
|
||||
name: "Sheet1",
|
||||
data: [
|
||||
[{ v: "0" }],
|
||||
[{ v: "1" }],
|
||||
[{ v: "2" }],
|
||||
[{ v: "3" }],
|
||||
[{ v: "4" }],
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const SetRowHeight: ComponentStory<typeof Workbook> = () => {
|
||||
const ref = useRef<WorkbookInstance>(null);
|
||||
useEffect(() => {
|
||||
ref.current?.setRowHeight({ "2": 100 });
|
||||
});
|
||||
return (
|
||||
<div style={{ width: "100%", height: "100%" }}>
|
||||
<Workbook
|
||||
ref={ref}
|
||||
data={[
|
||||
{
|
||||
name: "Sheet1",
|
||||
data: [
|
||||
[{ v: "0" }],
|
||||
[{ v: "1" }],
|
||||
[{ v: "height = 100" }],
|
||||
[{ v: "3" }],
|
||||
[{ v: "4" }],
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const SetColumnWidth: ComponentStory<typeof Workbook> = () => {
|
||||
const ref = useRef<WorkbookInstance>(null);
|
||||
useEffect(() => {
|
||||
ref.current?.setColumnWidth({ "2": 200 });
|
||||
});
|
||||
return (
|
||||
<div style={{ width: "100%", height: "100%" }}>
|
||||
<Workbook
|
||||
ref={ref}
|
||||
data={[
|
||||
{
|
||||
name: "Sheet1",
|
||||
data: [
|
||||
[
|
||||
{ v: "0" },
|
||||
{ v: "1" },
|
||||
{ v: "width = 200" },
|
||||
{ v: "3" },
|
||||
{ v: "4" },
|
||||
],
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
Loading…
Reference in New Issue
Block a user