@ubermensch1218/hwpxeditor 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +270 -0
- package/dist/index.cjs +9866 -1583
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +266 -8
- package/dist/index.d.ts +266 -8
- package/dist/index.js +9879 -1592
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -23,6 +23,28 @@ interface RunVM {
|
|
|
23
23
|
highlightColor: string | null;
|
|
24
24
|
letterSpacing: number | null;
|
|
25
25
|
charPrIdRef: string | null;
|
|
26
|
+
hasTab?: boolean;
|
|
27
|
+
hasFwSpace?: boolean;
|
|
28
|
+
hasLineBreak?: boolean;
|
|
29
|
+
hyperlink?: string;
|
|
30
|
+
}
|
|
31
|
+
interface MarginVM {
|
|
32
|
+
top: number;
|
|
33
|
+
bottom: number;
|
|
34
|
+
left: number;
|
|
35
|
+
right: number;
|
|
36
|
+
}
|
|
37
|
+
interface CellBorderStyleVM {
|
|
38
|
+
type: string;
|
|
39
|
+
width: string;
|
|
40
|
+
color: string;
|
|
41
|
+
}
|
|
42
|
+
interface CellStyleVM {
|
|
43
|
+
borderLeft: CellBorderStyleVM | null;
|
|
44
|
+
borderRight: CellBorderStyleVM | null;
|
|
45
|
+
borderTop: CellBorderStyleVM | null;
|
|
46
|
+
borderBottom: CellBorderStyleVM | null;
|
|
47
|
+
backgroundColor: string | null;
|
|
26
48
|
}
|
|
27
49
|
interface TableCellVM {
|
|
28
50
|
row: number;
|
|
@@ -33,23 +55,59 @@ interface TableCellVM {
|
|
|
33
55
|
heightPx: number;
|
|
34
56
|
text: string;
|
|
35
57
|
isAnchor: boolean;
|
|
58
|
+
borderFillIDRef: string | null;
|
|
59
|
+
vertAlign: string;
|
|
60
|
+
style: CellStyleVM | null;
|
|
36
61
|
}
|
|
37
62
|
interface TableVM {
|
|
38
63
|
rowCount: number;
|
|
39
64
|
colCount: number;
|
|
40
65
|
cells: TableCellVM[][];
|
|
41
66
|
tableIndex: number;
|
|
67
|
+
pageBreak: string;
|
|
68
|
+
repeatHeader: boolean;
|
|
69
|
+
widthHwp: number;
|
|
70
|
+
heightHwp: number;
|
|
71
|
+
outMargin: MarginVM;
|
|
72
|
+
inMargin: MarginVM;
|
|
73
|
+
columnWidths: number[];
|
|
74
|
+
borderFillIDRef: string | null;
|
|
42
75
|
}
|
|
43
76
|
interface ImageVM {
|
|
44
77
|
dataUrl: string;
|
|
45
78
|
widthPx: number;
|
|
46
79
|
heightPx: number;
|
|
80
|
+
widthHwp: number;
|
|
81
|
+
heightHwp: number;
|
|
47
82
|
binaryItemIdRef: string;
|
|
83
|
+
outMargin: MarginVM;
|
|
84
|
+
}
|
|
85
|
+
interface EquationVM {
|
|
86
|
+
script: string;
|
|
87
|
+
widthPx: number;
|
|
88
|
+
heightPx: number;
|
|
89
|
+
textColor: string;
|
|
90
|
+
font: string;
|
|
91
|
+
baseLine: number;
|
|
92
|
+
}
|
|
93
|
+
interface TextBoxVM {
|
|
94
|
+
text: string;
|
|
95
|
+
widthPx: number;
|
|
96
|
+
heightPx: number;
|
|
97
|
+
widthHwp: number;
|
|
98
|
+
heightHwp: number;
|
|
99
|
+
x: number;
|
|
100
|
+
y: number;
|
|
101
|
+
borderColor: string;
|
|
102
|
+
fillColor: string;
|
|
103
|
+
textBoxIndex: number;
|
|
48
104
|
}
|
|
49
105
|
interface ParagraphVM {
|
|
50
106
|
runs: RunVM[];
|
|
51
107
|
tables: TableVM[];
|
|
52
108
|
images: ImageVM[];
|
|
109
|
+
textBoxes: TextBoxVM[];
|
|
110
|
+
equations: EquationVM[];
|
|
53
111
|
alignment: string;
|
|
54
112
|
lineSpacing: number;
|
|
55
113
|
spacingBefore: number;
|
|
@@ -58,6 +116,28 @@ interface ParagraphVM {
|
|
|
58
116
|
marginLeftPx: number;
|
|
59
117
|
marginRightPx: number;
|
|
60
118
|
paragraphIndex: number;
|
|
119
|
+
defaultFontSize: number | null;
|
|
120
|
+
defaultFontFamily: string | null;
|
|
121
|
+
}
|
|
122
|
+
interface FootnoteVM {
|
|
123
|
+
marker: string;
|
|
124
|
+
text: string;
|
|
125
|
+
}
|
|
126
|
+
interface ColumnLayoutVM {
|
|
127
|
+
colCount: number;
|
|
128
|
+
sameGap: number;
|
|
129
|
+
type: string;
|
|
130
|
+
}
|
|
131
|
+
interface PageNumVM {
|
|
132
|
+
pos: string;
|
|
133
|
+
formatType: string;
|
|
134
|
+
sideChar: string;
|
|
135
|
+
}
|
|
136
|
+
interface PageBorderFillVM {
|
|
137
|
+
type: string;
|
|
138
|
+
borderFillIdRef: string;
|
|
139
|
+
textBorder: string;
|
|
140
|
+
fillArea: string;
|
|
61
141
|
}
|
|
62
142
|
interface SectionVM {
|
|
63
143
|
pageWidthPx: number;
|
|
@@ -66,11 +146,21 @@ interface SectionVM {
|
|
|
66
146
|
marginBottomPx: number;
|
|
67
147
|
marginLeftPx: number;
|
|
68
148
|
marginRightPx: number;
|
|
149
|
+
headerHeightPx: number;
|
|
150
|
+
footerHeightPx: number;
|
|
69
151
|
paragraphs: ParagraphVM[];
|
|
70
152
|
sectionIndex: number;
|
|
153
|
+
headerText: string;
|
|
154
|
+
footerText: string;
|
|
155
|
+
footnotes: FootnoteVM[];
|
|
156
|
+
endnotes: FootnoteVM[];
|
|
157
|
+
columnLayout: ColumnLayoutVM;
|
|
158
|
+
pageNum: PageNumVM | null;
|
|
159
|
+
pageBorderFill: PageBorderFillVM | null;
|
|
71
160
|
}
|
|
72
161
|
interface EditorViewModel {
|
|
73
162
|
sections: SectionVM[];
|
|
163
|
+
watermarkText: string;
|
|
74
164
|
}
|
|
75
165
|
declare function buildViewModel(doc: HwpxDocument): EditorViewModel;
|
|
76
166
|
|
|
@@ -84,18 +174,23 @@ interface ParagraphBlockProps {
|
|
|
84
174
|
sectionIndex: number;
|
|
85
175
|
/** Index of this paragraph within the section's paragraphs array */
|
|
86
176
|
localIndex: number;
|
|
177
|
+
/** Total number of paragraphs in this section (for merge/delete bounds) */
|
|
178
|
+
paragraphCount: number;
|
|
87
179
|
}
|
|
88
|
-
declare function ParagraphBlock({ paragraph, sectionIndex, localIndex, }: ParagraphBlockProps): react_jsx_runtime.JSX.Element;
|
|
180
|
+
declare function ParagraphBlock({ paragraph, sectionIndex, localIndex, paragraphCount, }: ParagraphBlockProps): react_jsx_runtime.JSX.Element;
|
|
89
181
|
|
|
90
182
|
interface RunSpanProps {
|
|
91
183
|
run: RunVM;
|
|
184
|
+
tabWidth?: number;
|
|
92
185
|
}
|
|
93
|
-
declare function RunSpan({ run }: RunSpanProps): react_jsx_runtime.JSX.Element;
|
|
186
|
+
declare function RunSpan({ run, tabWidth }: RunSpanProps): react_jsx_runtime.JSX.Element;
|
|
94
187
|
|
|
95
188
|
interface ImageBlockProps {
|
|
96
189
|
image: ImageVM;
|
|
190
|
+
selected?: boolean;
|
|
191
|
+
onClick?: () => void;
|
|
97
192
|
}
|
|
98
|
-
declare function ImageBlock({ image }: ImageBlockProps): react_jsx_runtime.JSX.Element;
|
|
193
|
+
declare function ImageBlock({ image, selected, onClick }: ImageBlockProps): react_jsx_runtime.JSX.Element;
|
|
99
194
|
|
|
100
195
|
interface TableBlockProps {
|
|
101
196
|
table: TableVM;
|
|
@@ -109,6 +204,7 @@ interface TableCellProps {
|
|
|
109
204
|
sectionIndex: number;
|
|
110
205
|
paragraphIndex: number;
|
|
111
206
|
tableIndex: number;
|
|
207
|
+
inMargin?: MarginVM;
|
|
112
208
|
}
|
|
113
209
|
declare function TableCell({ cell, sectionIndex, paragraphIndex, tableIndex, }: TableCellProps): react_jsx_runtime.JSX.Element | null;
|
|
114
210
|
|
|
@@ -124,9 +220,10 @@ interface ToolbarButtonProps {
|
|
|
124
220
|
onClick?: () => void;
|
|
125
221
|
title?: string;
|
|
126
222
|
size?: "sm" | "md";
|
|
223
|
+
layout?: "horizontal" | "vertical";
|
|
127
224
|
className?: string;
|
|
128
225
|
}
|
|
129
|
-
declare function ToolbarButton({ icon, label, active, disabled, onClick, title, size, className, }: ToolbarButtonProps): react_jsx_runtime.JSX.Element;
|
|
226
|
+
declare function ToolbarButton({ icon, label, active, disabled, onClick, title, size, layout, className, }: ToolbarButtonProps): react_jsx_runtime.JSX.Element;
|
|
130
227
|
|
|
131
228
|
interface ToolbarDropdownProps {
|
|
132
229
|
value: string;
|
|
@@ -229,7 +326,7 @@ declare function NewDocumentButton(): react_jsx_runtime.JSX.Element;
|
|
|
229
326
|
/**
|
|
230
327
|
* Constants for the HWPX editor UI — font lists, style presets, alignment/spacing options.
|
|
231
328
|
*/
|
|
232
|
-
declare const FONT_FAMILIES: readonly ["맑은 고딕", "함초롬돋움", "함초롬바탕", "나눔고딕", "나눔명조", "나눔바른고딕", "바탕", "돋움", "굴림", "궁서", "Arial", "Times New Roman", "Courier New", "Verdana", "Georgia"];
|
|
329
|
+
declare const FONT_FAMILIES: readonly ["맑은 고딕", "함초롬돋움", "함초롬바탕", "나눔고딕", "나눔명조", "나눔바른고딕", "Noto Sans KR", "Noto Serif KR", "교보손글씨 2024 박서우", "교보손글씨 2023 우선아", "학교안심 알림장", "바탕", "돋움", "굴림", "궁서", "Arial", "Times New Roman", "Courier New", "Verdana", "Georgia"];
|
|
233
330
|
type FontFamily = (typeof FONT_FAMILIES)[number];
|
|
234
331
|
declare const FONT_SIZES: readonly [8, 9, 10, 10.5, 11, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36, 48, 72];
|
|
235
332
|
interface StylePreset {
|
|
@@ -283,7 +380,8 @@ declare const HIGHLIGHT_COLORS: readonly [{
|
|
|
283
380
|
readonly value: "none";
|
|
284
381
|
readonly label: "없음";
|
|
285
382
|
}];
|
|
286
|
-
type
|
|
383
|
+
type OrientationType = "PORTRAIT" | "LANDSCAPE";
|
|
384
|
+
type SidebarTab = "char" | "para" | "page" | "img-layout" | "img-props" | "table" | "cell";
|
|
287
385
|
|
|
288
386
|
/**
|
|
289
387
|
* format-bridge.ts — Bridge between UI and @ubermensch1218/hwpxcore formatting APIs.
|
|
@@ -312,7 +410,7 @@ interface ParaFormat {
|
|
|
312
410
|
indentRight: number;
|
|
313
411
|
firstLineIndent: number;
|
|
314
412
|
}
|
|
315
|
-
declare function readCharFormat(style: RunStyle | null): CharFormat;
|
|
413
|
+
declare function readCharFormat(style: RunStyle | null, doc?: HwpxDocument | null): CharFormat;
|
|
316
414
|
declare function readParaFormat(doc: HwpxDocument, paragraph: HwpxOxmlParagraph): ParaFormat;
|
|
317
415
|
declare function readStyleInfo(doc: HwpxDocument, paragraph: HwpxOxmlParagraph): {
|
|
318
416
|
styleName: string | null;
|
|
@@ -327,23 +425,59 @@ declare function readFormatFromSelection(doc: HwpxDocument, sectionIndex: number
|
|
|
327
425
|
interface SelectionState {
|
|
328
426
|
sectionIndex: number;
|
|
329
427
|
paragraphIndex: number;
|
|
330
|
-
type: "paragraph" | "cell";
|
|
428
|
+
type: "paragraph" | "cell" | "table";
|
|
331
429
|
tableIndex?: number;
|
|
332
430
|
row?: number;
|
|
333
431
|
col?: number;
|
|
432
|
+
endRow?: number;
|
|
433
|
+
endCol?: number;
|
|
434
|
+
objectType?: "image" | "table" | "textBox";
|
|
435
|
+
imageIndex?: number;
|
|
436
|
+
textBoxIndex?: number;
|
|
437
|
+
textStartOffset?: number;
|
|
438
|
+
textEndOffset?: number;
|
|
334
439
|
}
|
|
335
440
|
interface ActiveFormat {
|
|
336
441
|
bold: boolean;
|
|
337
442
|
italic: boolean;
|
|
338
443
|
underline: boolean;
|
|
444
|
+
strikethrough: boolean;
|
|
339
445
|
}
|
|
340
446
|
interface ExtendedFormat {
|
|
341
447
|
char: CharFormat;
|
|
342
448
|
para: ParaFormat;
|
|
343
449
|
}
|
|
450
|
+
interface Template {
|
|
451
|
+
id: string;
|
|
452
|
+
name: string;
|
|
453
|
+
path: string;
|
|
454
|
+
description?: string;
|
|
455
|
+
createdAt: number;
|
|
456
|
+
}
|
|
344
457
|
interface UIState {
|
|
345
458
|
sidebarOpen: boolean;
|
|
346
459
|
sidebarTab: SidebarTab;
|
|
460
|
+
saveDialogOpen: boolean;
|
|
461
|
+
charFormatDialogOpen: boolean;
|
|
462
|
+
paraFormatDialogOpen: boolean;
|
|
463
|
+
bulletNumberDialogOpen: boolean;
|
|
464
|
+
charMapDialogOpen: boolean;
|
|
465
|
+
templateDialogOpen: boolean;
|
|
466
|
+
headerFooterDialogOpen: boolean;
|
|
467
|
+
findReplaceDialogOpen: boolean;
|
|
468
|
+
wordCountDialogOpen: boolean;
|
|
469
|
+
pageNumberDialogOpen: boolean;
|
|
470
|
+
styleDialogOpen: boolean;
|
|
471
|
+
autoCorrectDialogOpen: boolean;
|
|
472
|
+
outlineDialogOpen: boolean;
|
|
473
|
+
shapeDialogOpen: boolean;
|
|
474
|
+
tocDialogOpen: boolean;
|
|
475
|
+
zoomLevel: number;
|
|
476
|
+
}
|
|
477
|
+
interface UndoEntry {
|
|
478
|
+
sectionElements: Element[];
|
|
479
|
+
headerElements: Element[];
|
|
480
|
+
selection: SelectionState | null;
|
|
347
481
|
}
|
|
348
482
|
interface EditorStore {
|
|
349
483
|
doc: HwpxDocument | null;
|
|
@@ -355,6 +489,8 @@ interface EditorStore {
|
|
|
355
489
|
uiState: UIState;
|
|
356
490
|
loading: boolean;
|
|
357
491
|
error: string | null;
|
|
492
|
+
undoStack: UndoEntry[];
|
|
493
|
+
redoStack: UndoEntry[];
|
|
358
494
|
setDocument: (doc: HwpxDocument) => void;
|
|
359
495
|
rebuild: () => void;
|
|
360
496
|
setSelection: (sel: SelectionState | null) => void;
|
|
@@ -367,10 +503,132 @@ interface EditorStore {
|
|
|
367
503
|
toggleBold: () => void;
|
|
368
504
|
toggleItalic: () => void;
|
|
369
505
|
toggleUnderline: () => void;
|
|
506
|
+
toggleStrikethrough: () => void;
|
|
507
|
+
setFontFamily: (fontFamily: string) => void;
|
|
508
|
+
setFontSize: (size: number) => void;
|
|
509
|
+
setTextColor: (color: string) => void;
|
|
510
|
+
setHighlightColor: (color: string) => void;
|
|
511
|
+
setAlignment: (alignment: AlignmentType) => void;
|
|
512
|
+
setLineSpacing: (spacing: number) => void;
|
|
513
|
+
deleteBlock: (sectionIndex: number, paragraphIndex: number) => void;
|
|
514
|
+
insertBlockAt: (sectionIndex: number, paragraphIndex: number, text?: string) => void;
|
|
515
|
+
splitParagraph: (sectionIndex: number, paragraphIndex: number, offset: number) => void;
|
|
516
|
+
mergeParagraphWithPrevious: (sectionIndex: number, paragraphIndex: number) => void;
|
|
517
|
+
pushUndo: () => void;
|
|
518
|
+
undo: () => void;
|
|
519
|
+
redo: () => void;
|
|
370
520
|
addParagraph: (text?: string) => void;
|
|
371
521
|
addTable: (sectionIndex: number, paragraphIndex: number, rows: number, cols: number) => void;
|
|
372
522
|
insertImage: (data: Uint8Array, mediaType: string, widthMm: number, heightMm: number) => void;
|
|
523
|
+
insertColumnBreak: () => void;
|
|
524
|
+
insertPageBreak: () => void;
|
|
525
|
+
updatePictureSize: (widthMm: number, heightMm: number) => void;
|
|
526
|
+
resizeImage: (deltaWidthHwp: number, deltaHeightHwp: number) => void;
|
|
527
|
+
setImageOutMargin: (margins: Partial<{
|
|
528
|
+
top: number;
|
|
529
|
+
bottom: number;
|
|
530
|
+
left: number;
|
|
531
|
+
right: number;
|
|
532
|
+
}>) => void;
|
|
533
|
+
setTablePageBreak: (mode: "CELL" | "NONE") => void;
|
|
534
|
+
setTableRepeatHeader: (repeat: boolean) => void;
|
|
535
|
+
setTableSize: (widthMm: number, heightMm: number) => void;
|
|
536
|
+
setTableOutMargin: (margins: Partial<{
|
|
537
|
+
top: number;
|
|
538
|
+
bottom: number;
|
|
539
|
+
left: number;
|
|
540
|
+
right: number;
|
|
541
|
+
}>) => void;
|
|
542
|
+
setTableInMargin: (margins: Partial<{
|
|
543
|
+
top: number;
|
|
544
|
+
bottom: number;
|
|
545
|
+
left: number;
|
|
546
|
+
right: number;
|
|
547
|
+
}>) => void;
|
|
548
|
+
resizeTableColumn: (sectionIdx: number, paraIdx: number, tableIdx: number, colIdx: number, deltaHwp: number) => void;
|
|
549
|
+
setFirstLineIndent: (valueHwp: number) => void;
|
|
550
|
+
setLeftIndent: (valueHwp: number) => void;
|
|
551
|
+
setPageNumbering: (opts: {
|
|
552
|
+
position: string;
|
|
553
|
+
startNumber: number;
|
|
554
|
+
}) => void;
|
|
555
|
+
insertFootnote: () => void;
|
|
556
|
+
insertEndnote: () => void;
|
|
557
|
+
setWatermarkText: (text: string) => void;
|
|
558
|
+
openCharFormatDialog: () => void;
|
|
559
|
+
closeCharFormatDialog: () => void;
|
|
560
|
+
openParaFormatDialog: () => void;
|
|
561
|
+
closeParaFormatDialog: () => void;
|
|
562
|
+
openBulletNumberDialog: () => void;
|
|
563
|
+
closeBulletNumberDialog: () => void;
|
|
564
|
+
openCharMapDialog: () => void;
|
|
565
|
+
closeCharMapDialog: () => void;
|
|
566
|
+
openTemplateDialog: () => void;
|
|
567
|
+
closeTemplateDialog: () => void;
|
|
568
|
+
openHeaderFooterDialog: () => void;
|
|
569
|
+
closeHeaderFooterDialog: () => void;
|
|
570
|
+
openFindReplaceDialog: () => void;
|
|
571
|
+
closeFindReplaceDialog: () => void;
|
|
572
|
+
openWordCountDialog: () => void;
|
|
573
|
+
closeWordCountDialog: () => void;
|
|
574
|
+
openPageNumberDialog: () => void;
|
|
575
|
+
closePageNumberDialog: () => void;
|
|
576
|
+
openStyleDialog: () => void;
|
|
577
|
+
closeStyleDialog: () => void;
|
|
578
|
+
openAutoCorrectDialog: () => void;
|
|
579
|
+
closeAutoCorrectDialog: () => void;
|
|
580
|
+
openOutlineDialog: () => void;
|
|
581
|
+
closeOutlineDialog: () => void;
|
|
582
|
+
openShapeDialog: () => void;
|
|
583
|
+
closeShapeDialog: () => void;
|
|
584
|
+
openTocDialog: () => void;
|
|
585
|
+
closeTocDialog: () => void;
|
|
586
|
+
setZoom: (level: number) => void;
|
|
587
|
+
zoomIn: () => void;
|
|
588
|
+
zoomOut: () => void;
|
|
589
|
+
templates: Template[];
|
|
590
|
+
loadTemplates: () => void;
|
|
591
|
+
saveTemplates: () => void;
|
|
592
|
+
addTemplate: (name: string, path: string, description?: string) => void;
|
|
593
|
+
removeTemplate: (id: string) => void;
|
|
594
|
+
insertTextAtCursor: (text: string) => void;
|
|
595
|
+
insertTab: () => void;
|
|
596
|
+
updatePageSize: (width: number, height: number) => void;
|
|
597
|
+
updatePageMargins: (margins: Partial<{
|
|
598
|
+
left: number;
|
|
599
|
+
right: number;
|
|
600
|
+
top: number;
|
|
601
|
+
bottom: number;
|
|
602
|
+
header: number;
|
|
603
|
+
footer: number;
|
|
604
|
+
gutter: number;
|
|
605
|
+
}>) => void;
|
|
606
|
+
updatePageOrientation: (orientation: OrientationType) => void;
|
|
607
|
+
setCellBorder: (sides: ("left" | "right" | "top" | "bottom")[], style: {
|
|
608
|
+
type?: string;
|
|
609
|
+
width?: string;
|
|
610
|
+
color?: string;
|
|
611
|
+
}) => void;
|
|
612
|
+
setCellBackground: (color: string | null) => void;
|
|
613
|
+
setCellVertAlign: (align: "TOP" | "CENTER" | "BOTTOM") => void;
|
|
614
|
+
setTableBorder: (sides: ("left" | "right" | "top" | "bottom")[], style: {
|
|
615
|
+
type?: string;
|
|
616
|
+
width?: string;
|
|
617
|
+
color?: string;
|
|
618
|
+
}) => void;
|
|
619
|
+
setTableBackground: (color: string | null) => void;
|
|
620
|
+
insertTableRow: (position: "above" | "below") => void;
|
|
621
|
+
deleteTableRow: () => void;
|
|
622
|
+
insertTableColumn: (position: "left" | "right") => void;
|
|
623
|
+
deleteTableColumn: () => void;
|
|
624
|
+
mergeTableCells: () => void;
|
|
625
|
+
splitTableCell: () => void;
|
|
626
|
+
deleteTable: () => void;
|
|
627
|
+
openFile: () => void;
|
|
373
628
|
saveDocument: () => Promise<void>;
|
|
629
|
+
saveDocumentAs: (filename: string) => Promise<void>;
|
|
630
|
+
openSaveDialog: () => void;
|
|
631
|
+
closeSaveDialog: () => void;
|
|
374
632
|
setLoading: (loading: boolean) => void;
|
|
375
633
|
setError: (error: string | null) => void;
|
|
376
634
|
}
|