uni-answer-sheet 1.0.6 → 2.0.0

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.
@@ -0,0 +1,534 @@
1
+ /** JSON content shared across package boundaries; extensible node attributes. */
2
+ interface JSONContent {
3
+ type?: string;
4
+ attrs?: Record<string, any>;
5
+ content?: JSONContent[];
6
+ marks?: {
7
+ type: string;
8
+ attrs?: Record<string, any>;
9
+ }[];
10
+ text?: string;
11
+ }
12
+ type ImageUploadHandler = (file: File) => Promise<string>;
13
+ interface RichTextDocument {
14
+ version: 1;
15
+ content: JSONContent;
16
+ }
17
+ interface RichTextMetrics {
18
+ width: number;
19
+ height: number;
20
+ overflowing: boolean;
21
+ }
22
+ interface FlowSlice {
23
+ from: number;
24
+ to: number;
25
+ x: number;
26
+ y: number;
27
+ }
28
+ interface FlowUnit {
29
+ top: number;
30
+ bottom: number;
31
+ }
32
+ interface RichTextPagination {
33
+ slices: FlowSlice[];
34
+ /** Largest indivisible object that fits a full continuation column. */
35
+ maxUnitHeight?: number;
36
+ onMeasure: (units: FlowUnit[]) => void;
37
+ onActiveSliceChange?: (index: number) => void;
38
+ }
39
+ interface AnswerRegion {
40
+ id: string | null;
41
+ pos: number;
42
+ type: 'answerLine' | 'choiceMarker' | 'choiceOption' | 'answerCell';
43
+ attrs: Record<string, unknown>;
44
+ x: number;
45
+ y: number;
46
+ width: number;
47
+ height: number;
48
+ }
49
+ interface RichTextEditorProps {
50
+ initialValue?: RichTextDocument;
51
+ readOnly?: boolean;
52
+ maxHeight?: number;
53
+ className?: string;
54
+ ariaLabel?: string;
55
+ choiceFillStyle?: 'bubble' | 'check' | 'box';
56
+ choiceFillPosition?: 'stem' | 'option';
57
+ choiceFillBindings?: ChoiceFillBinding[];
58
+ /** Highlight a host-selected question without changing the rich-text document. */
59
+ activeChoiceQuestionId?: string;
60
+ /** Optional host identities; ordinary editors remain independent of card data. */
61
+ contentTargets?: ContentTarget[];
62
+ allowContentAssignment?: boolean;
63
+ onContentSelect?: (id: string) => void;
64
+ pagination?: RichTextPagination;
65
+ /** Upload a selected file and return its image URL. Omit to embed a data URL. */
66
+ uploadImage?: ImageUploadHandler;
67
+ onChange?: (document: RichTextDocument) => void;
68
+ onLayout?: (metrics: RichTextMetrics) => void;
69
+ }
70
+ interface ContentTarget {
71
+ id: string;
72
+ label: string;
73
+ kind: 'question' | 'material';
74
+ parentId?: string;
75
+ choice?: boolean;
76
+ hideOptionsAtStem?: boolean;
77
+ inlineOptions?: boolean;
78
+ optionWidth?: number;
79
+ }
80
+ interface ChoiceFillBinding {
81
+ groupId: string;
82
+ questionId: string;
83
+ options: {
84
+ id: string;
85
+ label: string;
86
+ contentOptionId: string;
87
+ }[];
88
+ }
89
+
90
+ /** Versioned, structural protocol. No React, Tiptap or package dependency. */
91
+ interface EditorStatus {
92
+ ready: boolean;
93
+ editable: boolean;
94
+ composing: boolean;
95
+ uploading: boolean;
96
+ layoutPending: boolean;
97
+ uploadError?: string;
98
+ }
99
+ interface EditorHandle {
100
+ getDocument(): RichTextDocument | null;
101
+ getAnswerRegions(): AnswerRegion[];
102
+ setDocument(value: RichTextDocument): void;
103
+ syncDocument(value: RichTextDocument): void;
104
+ focus(position?: 'start' | 'end'): void;
105
+ focusContent(id: string): boolean;
106
+ insertAnswerRegion(id: string, label: string, width?: number): void;
107
+ getStatus(): EditorStatus;
108
+ }
109
+ interface EditorInstance extends EditorHandle {
110
+ readonly ready: Promise<void>;
111
+ setOptions(options: Partial<RichTextEditorProps>): void;
112
+ destroy(): void;
113
+ }
114
+ interface QuestionHTMLCodec {
115
+ parse(html: string): RichTextDocument;
116
+ serialize(value: RichTextDocument): string;
117
+ unwrapParagraphs?(html: string, firstOnly?: boolean): string;
118
+ }
119
+ interface AnswerSheetEditorPlugin {
120
+ readonly kind: 'answer-sheet-editor';
121
+ readonly name: string;
122
+ readonly apiVersion: 1;
123
+ readonly documentVersion: 1;
124
+ /** The v1 surface exposes .rt-content and supports paginated flow slices. */
125
+ readonly capabilities: readonly string[];
126
+ /** Load the adapter before validating documents or using the HTML codec. */
127
+ prepare(): Promise<void>;
128
+ create(container: HTMLElement, options: RichTextEditorProps): EditorInstance;
129
+ readonly html: QuestionHTMLCodec;
130
+ /** Empty array means that the schema accepts the document. */
131
+ validateDocument(value: RichTextDocument): string[];
132
+ }
133
+
134
+ type ExerciseKind = 'judge' | 'fill' | 'answer' | 'calculation' | 'matching' | 'ordering' | 'correction' | 'drawing' | 'table' | 'writing' | 'english' | 'reading' | 'cloze' | 'completion' | 'chunk' | 'composite' | 'optional' | 'practice';
135
+ type ItemKind = 'choice' | 'judge' | 'fill' | 'answer' | 'calculation' | 'correction' | 'drawing' | 'table' | 'writing' | 'english';
136
+ type AreaStyle = 'blank' | 'lines' | 'grid' | 'characters' | 'four-lines' | 'coordinates';
137
+ interface AnswerBlank {
138
+ id: string;
139
+ label: string;
140
+ width: number;
141
+ style: 'line' | 'brackets' | 'box' | 'characters';
142
+ characters: number;
143
+ score: number | null;
144
+ answers: string[];
145
+ prefix: string;
146
+ suffix: string;
147
+ breakAfter: boolean;
148
+ }
149
+ interface ScoringStep {
150
+ id: string;
151
+ label: string;
152
+ score: number | null;
153
+ prompt: string;
154
+ answer: string;
155
+ }
156
+ interface AnswerArea {
157
+ style: AreaStyle;
158
+ rows: number;
159
+ columns: number;
160
+ rowHeight: number;
161
+ wordMark: number;
162
+ title: boolean;
163
+ backgroundUrl: string;
164
+ }
165
+ interface ExerciseItem {
166
+ id: string;
167
+ label: string;
168
+ kind: ItemKind;
169
+ document: RichTextDocument;
170
+ score: number | null;
171
+ reference: RichTextDocument;
172
+ explanation: RichTextDocument;
173
+ choice: CardChoiceQuestion;
174
+ presentation: CardChoiceSettings['presentation'];
175
+ blanks: AnswerBlank[];
176
+ steps: ScoringStep[];
177
+ area: AnswerArea;
178
+ needsReason: boolean;
179
+ judgment: boolean | null;
180
+ targets: string[];
181
+ }
182
+ interface ExerciseOption {
183
+ id: string;
184
+ label: string;
185
+ text: string;
186
+ document?: RichTextDocument;
187
+ }
188
+ interface ExerciseSettings {
189
+ items: ExerciseItem[];
190
+ judgeLabels: 'symbols' | 'letters' | 'words';
191
+ fillNewLine: boolean;
192
+ pool: ExerciseOption[];
193
+ relation: 'one' | 'many';
194
+ reuseOptions: boolean;
195
+ matchingDisplay: 'letters' | 'lines';
196
+ ordering: 'sequence' | 'category';
197
+ sequence: string[];
198
+ categories: ExerciseOption[];
199
+ assignments: Record<string, string>;
200
+ chooseCount: number;
201
+ groupScore: number | null;
202
+ chunkText: string;
203
+ chunkPoints: {
204
+ id: string;
205
+ offset: number;
206
+ label: string;
207
+ }[];
208
+ chunkCorrect: string[];
209
+ chunkMax: number;
210
+ chunkScore: number | null;
211
+ attachmentUrl: string;
212
+ }
213
+
214
+ type ChoiceMarkerStyle = 'letter' | 'bubble' | 'check' | 'box';
215
+ type ChoiceLayout = {
216
+ layout: 'fixed' | 'natural';
217
+ columns: number;
218
+ indent: boolean;
219
+ rowGap: number;
220
+ columnGap: number;
221
+ marker: ChoiceMarkerStyle;
222
+ };
223
+
224
+ interface ReferenceText {
225
+ content: RichTextDocument;
226
+ itemsContent: {
227
+ id: string;
228
+ key: string;
229
+ content: RichTextDocument;
230
+ }[];
231
+ groupId: string;
232
+ layout: ChoiceLayout;
233
+ numbered: boolean;
234
+ }
235
+ declare const questionTypes: {
236
+ readonly SCHOICE: "单选题";
237
+ readonly MCHOICE: "多选题";
238
+ readonly JUDGE: "判断题";
239
+ readonly FILLBLANK: "填空题";
240
+ readonly SHORTANSWER: "解答题";
241
+ readonly MIXED: "复合题";
242
+ readonly CLOZE: "完形填空";
243
+ readonly READTHENANSWER: "阅读理解";
244
+ readonly INFO_MATCHING: "信息匹配";
245
+ readonly TEXT_COMPLETION: "语法填空";
246
+ readonly ECOMPOSITION: "英语作文";
247
+ readonly CCOMPOSITION: "语文作文";
248
+ readonly CHUNK_CHOICE: "断句题";
249
+ };
250
+ type QuestionType = keyof typeof questionTypes;
251
+ type AtomicType = Exclude<QuestionType, 'MIXED'>;
252
+ interface ReferencePart {
253
+ referenceData?: Record<string, unknown>;
254
+ id: string;
255
+ label: string;
256
+ score: number | null;
257
+ width: number;
258
+ breakAfter: boolean;
259
+ height: number;
260
+ document: RichTextDocument;
261
+ choice: CardChoiceQuestion;
262
+ text?: ReferenceText;
263
+ }
264
+ interface ReferenceQuestion {
265
+ referenceData?: Record<string, unknown>;
266
+ id: string;
267
+ type: AtomicType;
268
+ label: string;
269
+ score: number | null;
270
+ choice: CardChoiceQuestion;
271
+ parts: ReferencePart[];
272
+ document: RichTextDocument;
273
+ height: number;
274
+ contentHeight: number;
275
+ characters: number;
276
+ lines: number;
277
+ halfPoint: boolean;
278
+ rightAnswers: number | null;
279
+ singleScore: number | null;
280
+ text?: ReferenceText;
281
+ }
282
+ interface ReferenceGroup {
283
+ sectionSeq?: string | number;
284
+ referenceData?: Record<string, unknown>;
285
+ textVersion?: 1;
286
+ material?: RichTextDocument;
287
+ type: QuestionType;
288
+ questions: ReferenceQuestion[];
289
+ layout: CardChoiceSettings;
290
+ fillNewLine: boolean;
291
+ optional: boolean;
292
+ choose: number;
293
+ optionalHeight: number;
294
+ scoreType?: 'LESS_SCORE' | 'ITEM_SCORE';
295
+ }
296
+
297
+ type CardPreset = 'a4' | 'a3-two' | 'a3-three';
298
+ type BlockKind = 'choice' | ExerciseKind;
299
+ type ChoiceScoreType = 'LESS_SCORE' | 'ITEM_SCORE';
300
+ interface CardChoiceQuestion {
301
+ id: string;
302
+ label: string;
303
+ options: {
304
+ id: string;
305
+ label: string;
306
+ }[];
307
+ multiple: boolean;
308
+ indefinite?: boolean;
309
+ score?: number | null;
310
+ scoreType?: ChoiceScoreType;
311
+ lessScore?: number;
312
+ correctIds: string[];
313
+ breakBefore: boolean;
314
+ contentTarget?: {
315
+ groupId: string;
316
+ optionIds: string[];
317
+ } | null;
318
+ }
319
+ interface CardChoiceSettings {
320
+ source: 'manual' | 'content';
321
+ presentation: 'concentrated' | 'distributed' | 'stem' | 'option';
322
+ direction: 'row' | 'column';
323
+ rowsPerColumn: number;
324
+ marker: 'bubble' | 'check' | 'box';
325
+ rowGap: number;
326
+ columnGap: number;
327
+ questions: CardChoiceQuestion[];
328
+ questionState?: Record<string, Pick<CardChoiceQuestion, 'multiple' | 'correctIds' | 'breakBefore'>>;
329
+ }
330
+ interface CardBlock {
331
+ id: string;
332
+ title: string;
333
+ kind: BlockKind;
334
+ document: RichTextDocument;
335
+ answerHeight: number;
336
+ choices?: CardChoiceSettings;
337
+ exercise?: ExerciseSettings;
338
+ reference?: ReferenceGroup;
339
+ }
340
+ interface CardDocument {
341
+ version: 1;
342
+ questionCard?: boolean;
343
+ title: string;
344
+ preset: CardPreset;
345
+ margin: number;
346
+ gap: number;
347
+ creation?: CardCreation;
348
+ header?: CardHeaderSettings;
349
+ paperTitle?: CardPaperTitle;
350
+ blocks: CardBlock[];
351
+ scanMarking?: boolean;
352
+ halfPoint?: boolean;
353
+ choiceDirection?: 'row' | 'column';
354
+ mergeObjective?: boolean;
355
+ }
356
+ interface CardPaperTitle {
357
+ id: string;
358
+ document: RichTextDocument;
359
+ height: number;
360
+ }
361
+ interface CardCreation {
362
+ mode: 'template' | 'exam';
363
+ name: string;
364
+ /** Display labels; codes are authoritative when present. */
365
+ grade: string;
366
+ subject: string;
367
+ gradeCode?: string;
368
+ courseCode?: string;
369
+ subjectCode?: string;
370
+ phaseCode?: 'P' | 'J' | 'S';
371
+ /** Reference template ID and exam-paper ID, retained without backend requests. */
372
+ id?: string | number;
373
+ exampaperId?: string | number;
374
+ createMode?: 'MANUALLY' | 'IMPORTED' | 'THIRD';
375
+ }
376
+ interface CardHeaderSettings {
377
+ focusText: boolean;
378
+ writeKaohao: boolean;
379
+ missExam: boolean;
380
+ mifeng: boolean;
381
+ kaohao: 'school' | 'code';
382
+ weishu: number;
383
+ }
384
+
385
+ interface ReferenceOptionData {
386
+ id?: string | number;
387
+ key: string;
388
+ content: string;
389
+ }
390
+ interface ReferenceQuestionData extends Record<string, unknown> {
391
+ questionId?: string | number;
392
+ questionPid?: string | number;
393
+ id?: string | number;
394
+ questiontypeCode: AtomicType;
395
+ seq?: string | number;
396
+ showSeq?: string | number;
397
+ showSeqs?: (string | number)[] | null;
398
+ itemShowNames?: (string | number)[] | null;
399
+ score?: number | null;
400
+ itemScores?: (number | null)[];
401
+ itemcount?: number;
402
+ lessScore?: number;
403
+ scoreType?: 'LESS_SCORE' | 'ITEM_SCORE';
404
+ rightAnswers?: number | null;
405
+ singleScore?: number | null;
406
+ childNum?: number;
407
+ content?: string;
408
+ itemsContent?: ReferenceOptionData[];
409
+ items?: ReferenceQuestionData[];
410
+ extension?: Record<string, unknown>;
411
+ }
412
+ interface ReferenceSectionData extends Record<string, unknown> {
413
+ sectionSeq: string | number;
414
+ sectionName: string;
415
+ sectionQuestionType: QuestionType;
416
+ questionInfolist: ReferenceQuestionData[];
417
+ content?: string;
418
+ }
419
+ interface ReferencePaperData {
420
+ sectionInfoList: ReferenceSectionData[];
421
+ quesTextMap?: Record<string, unknown>;
422
+ }
423
+
424
+ interface ValidationIssue {
425
+ code: string;
426
+ path: string;
427
+ message: string;
428
+ blockId?: string;
429
+ questionId?: string;
430
+ }
431
+ interface ValidationResult {
432
+ valid: boolean;
433
+ issues: ValidationIssue[];
434
+ }
435
+ declare class AnswerSheetDataError extends Error {
436
+ readonly issues: ValidationIssue[];
437
+ constructor(issues: ValidationIssue[]);
438
+ }
439
+
440
+ type PhaseCode = 'P' | 'J' | 'S';
441
+ interface GradeOption {
442
+ value: string;
443
+ label: string;
444
+ classify?: PhaseCode;
445
+ }
446
+ interface CourseOption {
447
+ value: string;
448
+ label: string;
449
+ subjectCode?: string;
450
+ custom?: boolean;
451
+ }
452
+ /** Pass the reference project's permission-filtered options, without fetching inside the plugin. */
453
+ interface AnswerSheetDictionaries {
454
+ grades?: readonly GradeOption[];
455
+ gradeCourseMap?: Readonly<Record<string, readonly CourseOption[]>>;
456
+ courseCodeToSubjectCode?: Readonly<Record<string, string>>;
457
+ defaultGradeCode?: string;
458
+ defaultCourseCode?: string;
459
+ }
460
+
461
+ /** Round-trippable source plus the reference project's sectionInfoList/quesTextMap. */
462
+ type AnswerSheetData = CardDocument & ReferencePaperData;
463
+ type SaveResult = {
464
+ ok: true;
465
+ data: AnswerSheetData;
466
+ } | {
467
+ ok: false;
468
+ issues: ValidationIssue[];
469
+ };
470
+ type AnswerSheetLayout = Partial<Pick<CardDocument, 'preset' | 'margin' | 'gap' | 'questionCard' | 'scanMarking' | 'halfPoint' | 'choiceDirection' | 'mergeObjective'>> & {
471
+ /** Reference field aliases; conflicting aliases are rejected. */
472
+ pageNum?: 1 | 2 | 3;
473
+ quesCard?: boolean;
474
+ scoreType?: boolean;
475
+ choiceType?: boolean;
476
+ mixOb?: boolean;
477
+ };
478
+ type AnswerSheetInitialization = Pick<CardCreation, 'name' | 'id' | 'exampaperId' | 'createMode'> & {
479
+ /** Defaults to template, matching the built-in creation dialog. */
480
+ mode?: CardCreation['mode'];
481
+ /** Paper preset, margins/gap in mm, and the existing page-layout switches. */
482
+ layout?: AnswerSheetLayout;
483
+ header?: Partial<CardHeaderSettings>;
484
+ } & ({
485
+ gradeCode: string;
486
+ courseCode: string;
487
+ subjectCode?: string;
488
+ grade?: string;
489
+ subject?: string;
490
+ } | {
491
+ grade: string;
492
+ subject: string;
493
+ gradeCode?: undefined;
494
+ courseCode?: undefined;
495
+ subjectCode?: undefined;
496
+ });
497
+ interface AnswerSheetOptions {
498
+ plugins: readonly AnswerSheetEditorPlugin[];
499
+ initialValue?: CardDocument;
500
+ /** Permission-filtered grades/courses. Omit to use reference base subject dictionaries. */
501
+ dictionaries?: AnswerSheetDictionaries;
502
+ readOnly?: boolean;
503
+ uploadImage?: ImageUploadHandler;
504
+ onChange?: (document: CardDocument) => void;
505
+ /** The built-in Save button calls this with the same result as save(). */
506
+ onSave?: (result: SaveResult) => void;
507
+ onError?: (error: Error) => void;
508
+ }
509
+ interface AnswerSheetInstance {
510
+ readonly ready: Promise<void>;
511
+ /** Create a blank card from host settings. Call immediately after mounting to skip the creation dialog. */
512
+ initialize(options: AnswerSheetInitialization): Promise<void>;
513
+ /** Draft snapshot, without completeness validation. */
514
+ getDocument(): CardDocument;
515
+ /** Restore saved data or a draft, resetting selection and undo history. */
516
+ load(data: CardDocument | AnswerSheetData): Promise<void>;
517
+ /** Alias of load(). */
518
+ setDocument(document: CardDocument): Promise<void>;
519
+ newDocument(creation: CardCreation): Promise<void>;
520
+ getReferenceData(): ReferencePaperData;
521
+ setReferenceData(data: ReferencePaperData | ReferenceSectionData[]): Promise<void>;
522
+ validate(): Promise<ValidationResult>;
523
+ /** Waits for input and pagination; failure never contains savable data. */
524
+ save(): Promise<SaveResult>;
525
+ setOptions(options: Partial<Omit<AnswerSheetOptions, 'plugins' | 'initialValue'>>): void;
526
+ focusIssue(issue: ValidationIssue): void;
527
+ destroy(): void;
528
+ }
529
+
530
+ /** Framework-free DOM entry. Browser-only code is loaded after an explicit mount. */
531
+ declare function createAnswerSheet(target: string | HTMLElement, options: AnswerSheetOptions): AnswerSheetInstance;
532
+
533
+ export { AnswerSheetDataError, createAnswerSheet };
534
+ export type { AnswerSheetData, AnswerSheetDictionaries, AnswerSheetEditorPlugin, AnswerSheetInitialization, AnswerSheetInstance, AnswerSheetLayout, AnswerSheetOptions, CardBlock, CardChoiceQuestion, CardChoiceSettings, CardCreation, CardDocument, CardHeaderSettings, CardPaperTitle, CardPreset, CourseOption, GradeOption, ImageUploadHandler, PhaseCode, QuestionType, ReferenceGroup, ReferencePaperData, ReferencePart, ReferenceQuestion, ReferenceSectionData, ReferenceText, RichTextDocument, SaveResult, ValidationIssue, ValidationResult };