quill-clausula 0.1.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.
- package/README.md +133 -0
- package/dist/actions/action-buttons.d.ts +2 -0
- package/dist/actions/drag-organizer.d.ts +54 -0
- package/dist/actions/floating-bar.d.ts +19 -0
- package/dist/actions/ghost-cut.d.ts +55 -0
- package/dist/actions/move-delta.d.ts +7 -0
- package/dist/assinatura/assinatura-renderer.d.ts +5 -0
- package/dist/assinatura/assinatura-sync.d.ts +12 -0
- package/dist/autofill.d.ts +22 -0
- package/dist/blots/assinatura-embed.d.ts +11 -0
- package/dist/blots/clausula-container.d.ts +4 -0
- package/dist/blots/clausula-item.d.ts +15 -0
- package/dist/blots/objeto-container.d.ts +4 -0
- package/dist/blots/objeto-item.d.ts +12 -0
- package/dist/blots/parte-container.d.ts +4 -0
- package/dist/blots/parte-item.d.ts +13 -0
- package/dist/export/exporter.d.ts +64 -0
- package/dist/formats/agreed.d.ts +9 -0
- package/dist/formats/ghost.d.ts +7 -0
- package/dist/formats/locked.d.ts +2 -0
- package/dist/formats/spacing.d.ts +13 -0
- package/dist/import/markdown-importer.d.ts +37 -0
- package/dist/index.d.ts +32 -0
- package/dist/module.d.ts +112 -0
- package/dist/numbering/counter.d.ts +18 -0
- package/dist/numbering/extenso.d.ts +9 -0
- package/dist/numbering/formatter.d.ts +2 -0
- package/dist/numbering/roman.d.ts +2 -0
- package/dist/partes/partes-counter.d.ts +25 -0
- package/dist/quill-clausula.cjs +25 -0
- package/dist/quill-clausula.css +856 -0
- package/dist/quill-clausula.mjs +1779 -0
- package/dist/toolbar/handler.d.ts +18 -0
- package/dist/types.d.ts +68 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# quill-clausula
|
|
2
|
+
|
|
3
|
+
Brazilian legal document formatting module for [Quill 2](https://quilljs.com) — auto-numbered **Cláusulas**, **Parágrafos**, **Incisos**, and **Alíneas**, plus contract **Partes** (CONTRATANTE/CONTRATADO), **OBJETO**, signature blocks, and per-clause Lock / Agree / Disagree workflow.
|
|
4
|
+
|
|
5
|
+
Also ships:
|
|
6
|
+
|
|
7
|
+
- **Markdown import** (`importMarkdown`) — AI-generated legal Markdown → Delta with live clause numbering
|
|
8
|
+
- **Markdown/HTML export** (`exportMarkdown` / `exportHTML`) — numbering labels materialized; MD is pandoc-friendly for DOCX pipelines
|
|
9
|
+
- **Ghost Cut** — non-destructive Ctrl+X ([Textualize's idea](https://ishmael.textualize.io/blog/ghost-cut/)): the selection fades instead of being deleted; Ctrl+V moves it atomically (single undo); Esc cancels
|
|
10
|
+
- **Clause organizer** — floating drag handle to reorder whole clause blocks (parent + children)
|
|
11
|
+
- **Word-style spacing** — `lineheight` and `spacing` (space-after) block formats
|
|
12
|
+
- Table export support (Quill 2's table module → pipe tables in MD, `<table>` in HTML)
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
npm install quill-clausula quill
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
```js
|
|
23
|
+
import Quill from 'quill';
|
|
24
|
+
import { register } from 'quill-clausula';
|
|
25
|
+
import 'quill-clausula/dist/quill-clausula.css';
|
|
26
|
+
import 'quill/dist/quill.snow.css';
|
|
27
|
+
|
|
28
|
+
register();
|
|
29
|
+
|
|
30
|
+
const quill = new Quill('#editor', {
|
|
31
|
+
theme: 'snow',
|
|
32
|
+
modules: {
|
|
33
|
+
toolbar: {
|
|
34
|
+
container: [
|
|
35
|
+
[
|
|
36
|
+
{ clausula: ['clausula', 'subclausula', 'paragrafo', 'inciso', 'alinea', false] },
|
|
37
|
+
{ parte: ['contratante', 'contratado', false] },
|
|
38
|
+
],
|
|
39
|
+
['objeto', 'assinatura'],
|
|
40
|
+
['bold', 'italic', 'underline'],
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
clausula: {
|
|
44
|
+
clausulaFormat: 'extenso', // CLÁUSULA PRIMEIRA —
|
|
45
|
+
paragrafoFormat: 'extenso', // Parágrafo Primeiro. / Parágrafo Único.
|
|
46
|
+
incisoFormat: 'roman', // I —, II —
|
|
47
|
+
alineaFormat: 'letter-parenthesis', // a), b)
|
|
48
|
+
currentUser: 'user1',
|
|
49
|
+
users: ['user1', 'user2'],
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Autofill
|
|
56
|
+
|
|
57
|
+
Type a trigger word at the start of a line followed by Space:
|
|
58
|
+
|
|
59
|
+
| Trigger | Result |
|
|
60
|
+
|---|---|
|
|
61
|
+
| `cl`, `clausula` | Cláusula |
|
|
62
|
+
| `sub`, `subclausula` | Sub-cláusula |
|
|
63
|
+
| `par`, `paragrafo`, `§` | Parágrafo |
|
|
64
|
+
| `inc`, `inciso` | Inciso |
|
|
65
|
+
| `al`, `alinea` | Alínea |
|
|
66
|
+
| `contratante`, `contratado` | Parte (with template) |
|
|
67
|
+
| `objeto` | Objeto |
|
|
68
|
+
|
|
69
|
+
Tab / Shift+Tab promote and demote clause levels.
|
|
70
|
+
|
|
71
|
+
## Numbering formats
|
|
72
|
+
|
|
73
|
+
- `clausulaFormat`: `extenso`, `numeric`, `numeric-padded`, `ordinal`, `abbreviation`, `regular`, `regular-padded`
|
|
74
|
+
- `subclausulaFormat`: `dotted` (1.1), `dotted-padded`, `numeric`, `extenso`
|
|
75
|
+
- `paragrafoFormat`: `extenso`, `uppercase`, `numeric`, `symbol` (§1º) — a single parágrafo renders as *Parágrafo Único*
|
|
76
|
+
- `incisoFormat`: `roman`, `roman-lower`
|
|
77
|
+
- `alineaFormat`: `letter-parenthesis`, `letter`
|
|
78
|
+
|
|
79
|
+
Change `module.options` at runtime and call `module.renumber()` to reformat.
|
|
80
|
+
|
|
81
|
+
## Import / Export
|
|
82
|
+
|
|
83
|
+
```js
|
|
84
|
+
import { importMarkdown, exportMarkdown, exportHTML } from 'quill-clausula';
|
|
85
|
+
|
|
86
|
+
// AI-generated legal Markdown -> Delta with clausula attributes
|
|
87
|
+
quill.setContents(importMarkdown(aiMarkdown));
|
|
88
|
+
|
|
89
|
+
// Delta -> pandoc-friendly Markdown / clean HTML (numbering materialized)
|
|
90
|
+
const module = quill.getModule('clausula');
|
|
91
|
+
const md = module.exportMarkdown(); // pipe into `pandoc -o contrato.docx`
|
|
92
|
+
const html = module.exportHTML(); // print / PDF / read-only display
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`importMarkdown` recognizes the patterns LLMs produce for Brazilian legal
|
|
96
|
+
documents (`## CLÁUSULA PRIMEIRA — ...`, `1.1`, `§1º`, `Parágrafo Único.`,
|
|
97
|
+
`I —`, `a)`, `CONTRATANTE:`, `OBJETO:`) and STRIPS the numbering labels — the
|
|
98
|
+
module re-materializes them, so numbering never goes stale in the editor.
|
|
99
|
+
|
|
100
|
+
## Persistence
|
|
101
|
+
|
|
102
|
+
Save and restore documents with **deltas only** (`quill.getContents()` / `quill.setContents()`).
|
|
103
|
+
|
|
104
|
+
> **Warning:** numbering labels ("CLÁUSULA PRIMEIRA — ", "1.1", "§1º") are presentation-only UI nodes. `quill.getSemanticHTML()` omits them, and saving `root.innerHTML` duplicates them on reload. For print/PDF HTML with numbering use `exportHTML()`; for DOCX use `exportMarkdown()` + pandoc.
|
|
105
|
+
|
|
106
|
+
## Editing UX
|
|
107
|
+
|
|
108
|
+
- **Ghost Cut**: Ctrl+X fades the selection (nothing is deleted, clipboard untouched, no undo entry); Ctrl+V moves it to the cursor as ONE undoable operation; Esc cancels. Full-line cuts carry the line format, so cutting a cláusula never leaves an orphaned number. Traditional cut = Ctrl+C + Backspace.
|
|
109
|
+
- **Clause organizer**: hover a cláusula and a ⋮⋮ handle appears on the left; drag it to move the whole block (cláusula + children) — numbering follows.
|
|
110
|
+
- **Tab / Shift+Tab** promote and demote clause levels; `destroy()` detaches everything for SPA unmounting.
|
|
111
|
+
|
|
112
|
+
## Options
|
|
113
|
+
|
|
114
|
+
| Option | Default | Description |
|
|
115
|
+
|---|---|---|
|
|
116
|
+
| `currentUser` | — | User id recording agree/disagree votes |
|
|
117
|
+
| `users` | — | All users that must agree before Sign enables |
|
|
118
|
+
| `showActions` | `true` | Per-clause Lock/Agree/Disagree/Conversation buttons |
|
|
119
|
+
| `showFloatingBar` | `true` | Global action bar (Agree All, Lock All, Sign…) |
|
|
120
|
+
| `showDragHandle` | `true` | Floating drag handle to reorder clause blocks |
|
|
121
|
+
| `onJudge` / `onShare` / `onSign` / `onConversation` | — | Callbacks for the corresponding buttons |
|
|
122
|
+
|
|
123
|
+
## Development
|
|
124
|
+
|
|
125
|
+
```sh
|
|
126
|
+
npm run dev # demo at localhost:5173
|
|
127
|
+
npm test # vitest
|
|
128
|
+
npm run build # dist/ (esm + cjs + css + types)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
|
|
133
|
+
MIT
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clause organizer — a floating drag handle (⋮⋮) that appears to the left of
|
|
3
|
+
* the cláusula under the mouse. Dragging it moves the WHOLE clause block
|
|
4
|
+
* (parent cláusula + its children) to another position; a drop indicator
|
|
5
|
+
* line shows the target boundary while dragging.
|
|
6
|
+
*
|
|
7
|
+
* The handle is an overlay on `quill.container` (never inside the editable
|
|
8
|
+
* DOM), so Quill's document model is untouched until the actual move, which
|
|
9
|
+
* the module performs as a single atomic delta.
|
|
10
|
+
*/
|
|
11
|
+
export interface DragBlock {
|
|
12
|
+
/** Clausula item blots: parent first, then its children */
|
|
13
|
+
items: any[];
|
|
14
|
+
}
|
|
15
|
+
export interface DragOrganizerCallbacks {
|
|
16
|
+
getBlocks: () => DragBlock[];
|
|
17
|
+
/** Move block `sourceIndex` to sit at boundary `targetBoundary` (0..blocks.length) */
|
|
18
|
+
moveBlock: (sourceIndex: number, targetBoundary: number) => void;
|
|
19
|
+
}
|
|
20
|
+
export declare class DragOrganizer {
|
|
21
|
+
private quill;
|
|
22
|
+
private callbacks;
|
|
23
|
+
private container;
|
|
24
|
+
private handle;
|
|
25
|
+
private indicator;
|
|
26
|
+
private hoveredBlockIndex;
|
|
27
|
+
private hoveredParentEl;
|
|
28
|
+
private hideTimer;
|
|
29
|
+
private dragging;
|
|
30
|
+
private dropBoundary;
|
|
31
|
+
private blockRects;
|
|
32
|
+
private onMouseMove;
|
|
33
|
+
private onMouseLeave;
|
|
34
|
+
private onPointerDown;
|
|
35
|
+
private onPointerMove;
|
|
36
|
+
private onPointerUp;
|
|
37
|
+
constructor(quill: any, callbacks: DragOrganizerCallbacks);
|
|
38
|
+
private hideHandle;
|
|
39
|
+
/** Hide with a grace period so the mouse can travel to the handle. */
|
|
40
|
+
private scheduleHide;
|
|
41
|
+
private cancelHide;
|
|
42
|
+
/**
|
|
43
|
+
* While a block is hovered, the strip from the handle to the block's
|
|
44
|
+
* right edge (with vertical slack) counts as "still hovering" — without
|
|
45
|
+
* it the handle vanishes as soon as the mouse leaves the text on its
|
|
46
|
+
* way to grab it.
|
|
47
|
+
*/
|
|
48
|
+
private isInReachCorridor;
|
|
49
|
+
private trackHover;
|
|
50
|
+
private startDrag;
|
|
51
|
+
private trackDrag;
|
|
52
|
+
private endDrag;
|
|
53
|
+
destroy(): void;
|
|
54
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface FloatingBarCallbacks {
|
|
2
|
+
onUndo?: () => void;
|
|
3
|
+
onAgreeAll?: () => void;
|
|
4
|
+
onDisagreeAll?: () => void;
|
|
5
|
+
onLockAll?: () => void;
|
|
6
|
+
onJudge?: () => void;
|
|
7
|
+
onShare?: () => void;
|
|
8
|
+
onSign?: () => void;
|
|
9
|
+
}
|
|
10
|
+
export declare function createFloatingBar(doc: Document, callbacks: FloatingBarCallbacks): HTMLDivElement;
|
|
11
|
+
/**
|
|
12
|
+
* Creates the undo warning modal overlay.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createUndoModal(doc: Document, onConfirm: () => void, onCancel: () => void): HTMLDivElement;
|
|
15
|
+
/**
|
|
16
|
+
* Check if all clausula items (leaf-level, non-parent) have all users agreed.
|
|
17
|
+
* Returns true only when every leaf item has `agreed[user] === true` for every user.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isContractFullyAgreed(allItems: HTMLElement[], users: string[]): boolean;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ghost Cut — a non-destructive cut, after Textualize's "ghost cut" idea
|
|
3
|
+
* (https://ishmael.textualize.io/blog/ghost-cut/):
|
|
4
|
+
*
|
|
5
|
+
* - **Ctrl+X / Cmd+X (or menu Cut)**: nothing is deleted and nothing touches
|
|
6
|
+
* the clipboard. The selection just fades — it becomes "ghost" content.
|
|
7
|
+
* No undo entry is created.
|
|
8
|
+
* - **Ctrl+V / Cmd+V**: the ghost content is moved to the cursor in ONE
|
|
9
|
+
* atomic delta — a single undo restores everything.
|
|
10
|
+
* - **Escape**: the ghost returns to normal, nothing changed.
|
|
11
|
+
* - A traditional destructive cut is still available as Ctrl+C + Backspace.
|
|
12
|
+
*
|
|
13
|
+
* When the selection covers whole line(s), the range is extended to include
|
|
14
|
+
* the trailing newline so line formats (clausula, parte, objeto) travel with
|
|
15
|
+
* the move — cutting a cláusula never leaves an orphaned numbered line
|
|
16
|
+
* behind.
|
|
17
|
+
*/
|
|
18
|
+
interface GhostRange {
|
|
19
|
+
index: number;
|
|
20
|
+
length: number;
|
|
21
|
+
}
|
|
22
|
+
/** Scans a delta for the contiguous extent of `ghost` formatted content. */
|
|
23
|
+
export declare function findGhostRange(delta: {
|
|
24
|
+
ops: any[];
|
|
25
|
+
}): GhostRange | null;
|
|
26
|
+
export declare class GhostCut {
|
|
27
|
+
private quill;
|
|
28
|
+
private isRangeLocked;
|
|
29
|
+
constructor(quill: any, options: {
|
|
30
|
+
isRangeLocked: (index: number, length: number) => boolean;
|
|
31
|
+
});
|
|
32
|
+
get active(): boolean;
|
|
33
|
+
private findRange;
|
|
34
|
+
/**
|
|
35
|
+
* Expands a selection to include the trailing newline when it covers the
|
|
36
|
+
* entire text of its line(s), so line formats move together.
|
|
37
|
+
*/
|
|
38
|
+
private expandToLineBoundary;
|
|
39
|
+
/** Handles a `cut` DOM event. Returns true when the event was consumed. */
|
|
40
|
+
handleCut(event: ClipboardEvent): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Lines fully covered by the ghost range get a line-level class so their
|
|
43
|
+
* UI labels ("CLÁUSULA SEGUNDA — ", "2.1", "Parágrafo Primeiro.") fade
|
|
44
|
+
* together with the content — the label is presentation DOM, not text,
|
|
45
|
+
* so the inline ghost format alone cannot reach it.
|
|
46
|
+
*/
|
|
47
|
+
private markGhostLines;
|
|
48
|
+
private clearGhostLines;
|
|
49
|
+
/** Handles a `paste` DOM event. Returns true when the event was consumed. */
|
|
50
|
+
handlePaste(event: ClipboardEvent): boolean;
|
|
51
|
+
/** Cancels an active ghost (Escape). Returns true when one was cleared. */
|
|
52
|
+
cancel(): boolean;
|
|
53
|
+
destroy(): void;
|
|
54
|
+
}
|
|
55
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the op list for an atomic "move" delta: remove `length` characters
|
|
3
|
+
* at `start` and re-insert them (as `sliceOps`) at `target`, where `target`
|
|
4
|
+
* is a position in the PRE-move document. The result applies as a single
|
|
5
|
+
* updateContents call — one history entry, fully undoable.
|
|
6
|
+
*/
|
|
7
|
+
export declare function buildMoveOps(start: number, length: number, target: number, sliceOps: Array<Record<string, unknown>>): Array<Record<string, unknown>>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SignatureLine } from '../types.js';
|
|
2
|
+
interface ParteBlotLike {
|
|
3
|
+
domNode: HTMLElement;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Extracts signature lines from parte blots.
|
|
7
|
+
*
|
|
8
|
+
* For each parte, the "name" is the text content before the first comma.
|
|
9
|
+
* If no comma is found, the entire text content is used.
|
|
10
|
+
*/
|
|
11
|
+
export declare function extractSignatureLines(parteItems: ParteBlotLike[]): SignatureLine[];
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ClausulaType } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Extra triggers for non-clausula formats (parte, objeto).
|
|
4
|
+
* Returns { format, value } for applying to the line.
|
|
5
|
+
*/
|
|
6
|
+
export interface ExtraTriggerResult {
|
|
7
|
+
format: string;
|
|
8
|
+
value: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The full regex that matches any trigger word at the start of a line.
|
|
12
|
+
* Used as the `prefix` in the keyboard binding.
|
|
13
|
+
*/
|
|
14
|
+
export declare const AUTOFILL_PREFIX: RegExp;
|
|
15
|
+
/**
|
|
16
|
+
* Given a matched prefix string, return the corresponding clausula type.
|
|
17
|
+
*/
|
|
18
|
+
export declare function matchTrigger(prefix: string): ClausulaType | null;
|
|
19
|
+
/**
|
|
20
|
+
* Given a matched prefix string, return a non-clausula format trigger if matched.
|
|
21
|
+
*/
|
|
22
|
+
export declare function matchExtraTrigger(prefix: string): ExtraTriggerResult | null;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AssinaturaConfig } from '../types.js';
|
|
2
|
+
declare const BlockEmbed: any;
|
|
3
|
+
declare class AssinaturaEmbed extends BlockEmbed {
|
|
4
|
+
static blotName: string;
|
|
5
|
+
static tagName: "DIV";
|
|
6
|
+
static className: string;
|
|
7
|
+
static create(value: AssinaturaConfig | string): HTMLElement;
|
|
8
|
+
static value(domNode: HTMLElement): AssinaturaConfig;
|
|
9
|
+
static formats(domNode: HTMLElement): undefined;
|
|
10
|
+
}
|
|
11
|
+
export default AssinaturaEmbed;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ClausulaType } from '../types.js';
|
|
2
|
+
declare const Block: any;
|
|
3
|
+
declare class ClausulaItem extends Block {
|
|
4
|
+
static blotName: string;
|
|
5
|
+
static tagName: "DIV";
|
|
6
|
+
static className: string;
|
|
7
|
+
actionsNode: HTMLElement | null;
|
|
8
|
+
static create(value: ClausulaType): HTMLElement;
|
|
9
|
+
static formats(domNode: HTMLElement): string | undefined;
|
|
10
|
+
static register(): void;
|
|
11
|
+
constructor(scroll: any, domNode: HTMLElement);
|
|
12
|
+
format(name: string, value: string): void;
|
|
13
|
+
update(mutations: MutationRecord[], context: Record<string, any>): void;
|
|
14
|
+
}
|
|
15
|
+
export default ClausulaItem;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
declare const Block: any;
|
|
2
|
+
declare class ObjetoItem extends Block {
|
|
3
|
+
static blotName: string;
|
|
4
|
+
static tagName: "DIV";
|
|
5
|
+
static className: string;
|
|
6
|
+
static create(value: string): HTMLElement;
|
|
7
|
+
static formats(domNode: HTMLElement): "true" | undefined;
|
|
8
|
+
static register(): void;
|
|
9
|
+
constructor(scroll: any, domNode: HTMLElement);
|
|
10
|
+
format(name: string, value: string): void;
|
|
11
|
+
}
|
|
12
|
+
export default ObjetoItem;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ParteType } from '../types.js';
|
|
2
|
+
declare const Block: any;
|
|
3
|
+
declare class ParteItem extends Block {
|
|
4
|
+
static blotName: string;
|
|
5
|
+
static tagName: "DIV";
|
|
6
|
+
static className: string;
|
|
7
|
+
static create(value: ParteType): HTMLElement;
|
|
8
|
+
static formats(domNode: HTMLElement): string | undefined;
|
|
9
|
+
static register(): void;
|
|
10
|
+
constructor(scroll: any, domNode: HTMLElement);
|
|
11
|
+
format(name: string, value: string): void;
|
|
12
|
+
}
|
|
13
|
+
export default ParteItem;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { AssinaturaConfig, ClausulaModuleOptions, ClausulaType, ParteType } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Delta-based document export.
|
|
4
|
+
*
|
|
5
|
+
* The delta is the single source of truth for persistence; numbering labels
|
|
6
|
+
* ("CLÁUSULA PRIMEIRA — ", "1.1", "§1º") exist only as presentation-side UI
|
|
7
|
+
* nodes and are NOT part of the delta. These exporters re-materialize the
|
|
8
|
+
* labels from the delta's line attributes, producing output that carries the
|
|
9
|
+
* full legal numbering:
|
|
10
|
+
*
|
|
11
|
+
* - `exportMarkdown` → pandoc-friendly Markdown (e.g. for DOCX conversion)
|
|
12
|
+
* - `exportHTML` → clean, class-annotated HTML (print / PDF / preview)
|
|
13
|
+
*/
|
|
14
|
+
interface DeltaOp {
|
|
15
|
+
insert?: string | Record<string, unknown>;
|
|
16
|
+
attributes?: Record<string, any>;
|
|
17
|
+
}
|
|
18
|
+
export interface DeltaLike {
|
|
19
|
+
ops: DeltaOp[];
|
|
20
|
+
}
|
|
21
|
+
export interface ExportSegment {
|
|
22
|
+
text: string;
|
|
23
|
+
bold?: boolean;
|
|
24
|
+
italic?: boolean;
|
|
25
|
+
underline?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface ExportLine {
|
|
28
|
+
kind: 'clausula' | 'parte' | 'objeto' | 'assinatura' | 'table-cell' | 'text';
|
|
29
|
+
/** Row identifier when kind is 'table-cell' (cells of the same row share it) */
|
|
30
|
+
tableRow?: string;
|
|
31
|
+
clausulaType?: ClausulaType;
|
|
32
|
+
parteType?: ParteType;
|
|
33
|
+
/** Materialized numbering/prefix label ('' when not applicable) */
|
|
34
|
+
label: string;
|
|
35
|
+
/** Plain text content of the line */
|
|
36
|
+
text: string;
|
|
37
|
+
segments: ExportSegment[];
|
|
38
|
+
locked?: boolean;
|
|
39
|
+
agreed?: Record<string, boolean>;
|
|
40
|
+
assinatura?: AssinaturaConfig;
|
|
41
|
+
/** Word-style spacing (CSS values), when set on the line */
|
|
42
|
+
lineHeight?: string;
|
|
43
|
+
spacingAfter?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Parses a delta into a flat list of logical lines with materialized
|
|
47
|
+
* numbering labels. This is the shared document model both exporters use.
|
|
48
|
+
*/
|
|
49
|
+
export declare function parseDeltaToLines(delta: DeltaLike, options: ClausulaModuleOptions): ExportLine[];
|
|
50
|
+
/**
|
|
51
|
+
* Exports a delta as pandoc-friendly Markdown with all numbering labels
|
|
52
|
+
* materialized. Cláusulas become `##` headings (mapping to Heading 2 in
|
|
53
|
+
* DOCX); every other label is emitted as literal bold text so pandoc/word
|
|
54
|
+
* processors never renumber the legal structure.
|
|
55
|
+
*/
|
|
56
|
+
export declare function exportMarkdown(delta: DeltaLike, options: ClausulaModuleOptions): string;
|
|
57
|
+
/**
|
|
58
|
+
* Exports a delta as clean, self-describing HTML with all numbering labels
|
|
59
|
+
* materialized — suitable for print, PDF generation, or read-only display
|
|
60
|
+
* outside the editor. (Unlike `quill.getSemanticHTML()`, which omits the
|
|
61
|
+
* labels, and `quill.root.innerHTML`, which duplicates them on reload.)
|
|
62
|
+
*/
|
|
63
|
+
export declare function exportHTML(delta: DeltaLike, options: ClausulaModuleOptions): string;
|
|
64
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
declare const Attributor: any;
|
|
2
|
+
declare class AgreedAttributor extends Attributor {
|
|
3
|
+
constructor(attrName: string, keyName: string, options?: Record<string, unknown>);
|
|
4
|
+
add(node: HTMLElement, value: Record<string, boolean> | string): boolean;
|
|
5
|
+
remove(node: HTMLElement): void;
|
|
6
|
+
value(node: HTMLElement): Record<string, boolean> | undefined;
|
|
7
|
+
}
|
|
8
|
+
declare const Agreed: AgreedAttributor;
|
|
9
|
+
export default Agreed;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transient inline format used by Ghost Cut: text marked `ghost` is the
|
|
3
|
+
* faded, inert content awaiting a paste-to-move. It is applied and removed
|
|
4
|
+
* with SILENT source (no history entries) and never survives an export.
|
|
5
|
+
*/
|
|
6
|
+
declare const GhostAttribute: any;
|
|
7
|
+
export default GhostAttribute;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Word-style spacing controls, stored in the delta as line attributes:
|
|
3
|
+
*
|
|
4
|
+
* - `lineheight`: line spacing within the paragraph (Word's "entre linhas")
|
|
5
|
+
* - `spacing`: space after the paragraph (Word's "depois do parágrafo")
|
|
6
|
+
*
|
|
7
|
+
* Both are plain CSS style attributors, so they survive copy/paste and
|
|
8
|
+
* export naturally as inline styles.
|
|
9
|
+
*/
|
|
10
|
+
export declare const LINE_HEIGHTS: readonly ["1", "1.15", "1.5", "2", "2.5", "3"];
|
|
11
|
+
export declare const PARAGRAPH_SPACINGS: readonly ["0em", "0.5em", "1em", "1.5em", "2em"];
|
|
12
|
+
export declare const LineHeightAttribute: any;
|
|
13
|
+
export declare const ParagraphSpacingAttribute: any;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { DeltaLike } from '../export/exporter.js';
|
|
2
|
+
/**
|
|
3
|
+
* Markdown → Quill Delta importer.
|
|
4
|
+
*
|
|
5
|
+
* Converts AI-generated Brazilian legal documents (Markdown) into a Delta
|
|
6
|
+
* whose lines carry quill-clausula attributes (`clausula`, `parte`,
|
|
7
|
+
* `objeto`), with numbering labels STRIPPED — the module re-materializes
|
|
8
|
+
* them dynamically, so imported numbers never go stale when clauses are
|
|
9
|
+
* added, removed, or reordered in the editor.
|
|
10
|
+
*
|
|
11
|
+
* Recognized patterns (tolerant to the typical LLM output variance):
|
|
12
|
+
*
|
|
13
|
+
* ## CLÁUSULA PRIMEIRA — DO OBJETO → clausula (text: "DO OBJETO")
|
|
14
|
+
* CLÁUSULA 2ª - DO PREÇO → clausula
|
|
15
|
+
* **1.1** texto / 1.1 texto / 1.1. texto → subclausula
|
|
16
|
+
* §1º texto / § 2º. texto → paragrafo
|
|
17
|
+
* Parágrafo Único. texto / **Parágrafo Primeiro.** texto → paragrafo
|
|
18
|
+
* I — texto / IV - texto → inciso
|
|
19
|
+
* a) texto / b) texto → alinea
|
|
20
|
+
* CONTRATANTE: texto / **CONTRATADA:** texto → parte
|
|
21
|
+
* OBJETO: texto → objeto
|
|
22
|
+
*
|
|
23
|
+
* Inline `**bold**`, `*italic*` and `_italic_` are converted to Quill
|
|
24
|
+
* attributes. YAML frontmatter is dropped.
|
|
25
|
+
*/
|
|
26
|
+
interface InsertOp {
|
|
27
|
+
insert: string;
|
|
28
|
+
attributes?: Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
/** Minimal inline Markdown parser: **bold**, *italic*, _italic_. */
|
|
31
|
+
export declare function parseInline(text: string): InsertOp[];
|
|
32
|
+
/**
|
|
33
|
+
* Converts legal-document Markdown into a Quill Delta with quill-clausula
|
|
34
|
+
* line attributes. Feed the result to `quill.setContents(...)`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function importMarkdown(markdown: string): DeltaLike;
|
|
37
|
+
export {};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import ClausulaModule from './module.js';
|
|
2
|
+
import ClausulaItem from './blots/clausula-item.js';
|
|
3
|
+
import ClausulaContainer from './blots/clausula-container.js';
|
|
4
|
+
import ParteItem from './blots/parte-item.js';
|
|
5
|
+
import ParteContainer from './blots/parte-container.js';
|
|
6
|
+
import ObjetoItem from './blots/objeto-item.js';
|
|
7
|
+
import ObjetoContainer from './blots/objeto-container.js';
|
|
8
|
+
import AssinaturaEmbed from './blots/assinatura-embed.js';
|
|
9
|
+
import LockedAttribute from './formats/locked.js';
|
|
10
|
+
import AgreedAttribute from './formats/agreed.js';
|
|
11
|
+
import GhostAttribute from './formats/ghost.js';
|
|
12
|
+
import { LineHeightAttribute, ParagraphSpacingAttribute } from './formats/spacing.js';
|
|
13
|
+
export declare function register(): void;
|
|
14
|
+
export { createActionButtons, syncButtonState } from './actions/action-buttons.js';
|
|
15
|
+
export { createFloatingBar, createUndoModal, isContractFullyAgreed } from './actions/floating-bar.js';
|
|
16
|
+
export { ClausulaModule, ClausulaItem, ClausulaContainer, ParteItem, ParteContainer, ObjetoItem, ObjetoContainer, AssinaturaEmbed, LockedAttribute, AgreedAttribute, GhostAttribute, LineHeightAttribute, ParagraphSpacingAttribute, };
|
|
17
|
+
export { LINE_HEIGHTS, PARAGRAPH_SPACINGS } from './formats/spacing.js';
|
|
18
|
+
export type { ClausulaType, ClausulaFormat, SubclausulaFormat, ParagrafoFormat, IncisoFormat, AlineaFormat, ClausulaModuleOptions, ClausulaIndex, ConversationContext, ParteType, ParteIndex, AssinaturaConfig, SignatureLine, } from './types.js';
|
|
19
|
+
export { toExtenso, toExtensoUpper } from './numbering/extenso.js';
|
|
20
|
+
export { toRoman, toRomanLower } from './numbering/roman.js';
|
|
21
|
+
export { computeIndices, computeIndicesFromTypes } from './numbering/counter.js';
|
|
22
|
+
export { formatLabel } from './numbering/formatter.js';
|
|
23
|
+
export { computeParteIndices, computeParteIndicesFromTypes, formatParteLabel } from './partes/partes-counter.js';
|
|
24
|
+
export { extractSignatureLines } from './assinatura/assinatura-sync.js';
|
|
25
|
+
export { renderAssinatura } from './assinatura/assinatura-renderer.js';
|
|
26
|
+
export { matchTrigger, matchExtraTrigger, AUTOFILL_PREFIX } from './autofill.js';
|
|
27
|
+
export { exportMarkdown, exportHTML, parseDeltaToLines } from './export/exporter.js';
|
|
28
|
+
export type { ExportLine, ExportSegment, DeltaLike } from './export/exporter.js';
|
|
29
|
+
export { importMarkdown, parseInline } from './import/markdown-importer.js';
|
|
30
|
+
export { GhostCut, findGhostRange } from './actions/ghost-cut.js';
|
|
31
|
+
export { DragOrganizer } from './actions/drag-organizer.js';
|
|
32
|
+
export { buildMoveOps } from './actions/move-delta.js';
|