@quario/editor 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/CHANGELOG.md +39 -0
- package/LICENSE +219 -0
- package/README.md +89 -0
- package/lib/chrome.js +431 -0
- package/lib/document.js +674 -0
- package/lib/history.js +57 -0
- package/lib/index.d.ts +119 -0
- package/lib/index.js +820 -0
- package/lib/rail.js +506 -0
- package/lib/register.d.ts +9 -0
- package/lib/register.js +10 -0
- package/lib/stage.js +654 -0
- package/lib/style.js +85 -0
- package/package.json +77 -0
package/lib/history.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The undo stack: a capped list of whole-document snapshots, each
|
|
3
|
+
* `{ schema, selection }`. Snapshots make undo correct by construction — no
|
|
4
|
+
* op vocabulary, no path transforms, no inverse functions — and a
|
|
5
|
+
* structuredClone of a few-KB schema is free beside the recompile every edit
|
|
6
|
+
* already pays (docs/adr/0031-undo-is-a-snapshot-stack.md).
|
|
7
|
+
*
|
|
8
|
+
* One entry per commit, and a commit is the end of a gesture. Entry zero is
|
|
9
|
+
* the seeded document, even when invalid — committed-but-invalid is
|
|
10
|
+
* legitimate and undoable; only per-character states stay out.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
let CAP = 100;
|
|
14
|
+
|
|
15
|
+
/** @type {(schema: any, selection: string | null) => { schema: any, selection: string | null }} */
|
|
16
|
+
let entry = (schema, selection) => ({ schema: structuredClone(schema), selection });
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {any} schema The seed document — history entry zero.
|
|
20
|
+
* @param {string | null} [selection]
|
|
21
|
+
*/
|
|
22
|
+
export function history(schema, selection = null) {
|
|
23
|
+
let entries = [entry(schema, selection)];
|
|
24
|
+
let at = 0;
|
|
25
|
+
return {
|
|
26
|
+
/** The current entry's schema — what undo/redo restore into the editor. */
|
|
27
|
+
get current() {
|
|
28
|
+
return entries[at];
|
|
29
|
+
},
|
|
30
|
+
get canUndo() {
|
|
31
|
+
return at > 0;
|
|
32
|
+
},
|
|
33
|
+
get canRedo() {
|
|
34
|
+
return at < entries.length - 1;
|
|
35
|
+
},
|
|
36
|
+
/** One commit per gesture: truncates redo, caps by dropping oldest. */
|
|
37
|
+
/** @type {(schema: any, selection: string | null) => void} */
|
|
38
|
+
commit(schema, selection) {
|
|
39
|
+
entries.length = at + 1;
|
|
40
|
+
entries.push(entry(schema, selection));
|
|
41
|
+
if (entries.length > CAP) entries.shift();
|
|
42
|
+
at = entries.length - 1;
|
|
43
|
+
},
|
|
44
|
+
/** @type {() => { schema: any, selection: string | null } | null} */
|
|
45
|
+
undo() {
|
|
46
|
+
if (at === 0) return null;
|
|
47
|
+
at -= 1;
|
|
48
|
+
return entries[at];
|
|
49
|
+
},
|
|
50
|
+
/** @type {() => { schema: any, selection: string | null } | null} */
|
|
51
|
+
redo() {
|
|
52
|
+
if (at === entries.length - 1) return null;
|
|
53
|
+
at += 1;
|
|
54
|
+
return entries[at];
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import type { LitElement } from "lit";
|
|
2
|
+
import type { Problem, Quario, ReportSchema, Target } from "quario";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Sheet geometry, in PostScript points — the same vocabulary the viewer's
|
|
6
|
+
* `page` takes (the pdf target's page sizes), purely visual: sheet width and
|
|
7
|
+
* padding, so preview and export agree.
|
|
8
|
+
*/
|
|
9
|
+
export interface EditorPage {
|
|
10
|
+
/** Named size or `[width, height]` in points. Default `'A4'`. */
|
|
11
|
+
size?: "A4" | "letter" | [number, number];
|
|
12
|
+
/** Margin on all four sides, in points. Default `54` (0.75 in). */
|
|
13
|
+
margin?: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** The `change` event's payload: the committed document, with its problems. */
|
|
17
|
+
export interface EditorChangeDetail {
|
|
18
|
+
/**
|
|
19
|
+
* The edited document, deep-frozen — the host cannot corrupt the editor's
|
|
20
|
+
* state by mutating it, and assigning this exact object back to `schema`
|
|
21
|
+
* is a no-op, so a naive persist-and-restore loop does not wipe the
|
|
22
|
+
* author's history.
|
|
23
|
+
*/
|
|
24
|
+
schema: ReportSchema;
|
|
25
|
+
/**
|
|
26
|
+
* The structured problem list of that document, from the engine's
|
|
27
|
+
* `plan()` — empty when it compiles. Save buttons disable on it without
|
|
28
|
+
* re-running the engine.
|
|
29
|
+
*/
|
|
30
|
+
problems: readonly Problem[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Which failure an `error` event names. */
|
|
34
|
+
export type EditorErrorKind = "mount-render" | "update-render" | "target";
|
|
35
|
+
|
|
36
|
+
/** The `error` event's payload. */
|
|
37
|
+
export interface EditorErrorDetail {
|
|
38
|
+
/** The caught value, exactly as thrown. */
|
|
39
|
+
error: unknown;
|
|
40
|
+
kind: EditorErrorKind;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The embeddable banded document designer, `<quario-editor>`. Assign
|
|
45
|
+
* `schema` (the starter document), `instance` (a quario instance — its
|
|
46
|
+
* `plan()` is the editor's loop, and the licence rides on it exactly as it
|
|
47
|
+
* does for the viewer), `target` (the html target, made with
|
|
48
|
+
* `html({ paths: true })` so rendered output maps back to the schema), and
|
|
49
|
+
* `data` (the sample the preview renders on); listen for `change` and
|
|
50
|
+
* `error`. Importing this module defines nothing — import
|
|
51
|
+
* `@quario/editor/register` for the one-line define, or call
|
|
52
|
+
* `customElements.define` with a tag of your own.
|
|
53
|
+
*
|
|
54
|
+
* The editor is uncontrolled: `schema` seeds it and the editor owns the
|
|
55
|
+
* document thereafter. Only a **new** `schema` object identity resets the
|
|
56
|
+
* document, history and selection; assigning back the object the last
|
|
57
|
+
* `change` delivered is a no-op. A new `instance`, `target`, `functions`,
|
|
58
|
+
* `data` or `page` recompiles and re-renders while leaving the author's
|
|
59
|
+
* work — document, history, selection — untouched. `colorScheme` repaints
|
|
60
|
+
* chrome only; the sheet stays white regardless.
|
|
61
|
+
*
|
|
62
|
+
* Host mistakes (a wrong target, a malformed page) throw `TypeError`s naming
|
|
63
|
+
* the property, delivered through the `error` event and the error panel.
|
|
64
|
+
* Removal is not destruction: the document and history persist, and
|
|
65
|
+
* reconnecting re-renders from them.
|
|
66
|
+
*/
|
|
67
|
+
export class QuarioEditor extends LitElement {
|
|
68
|
+
/** The starter document. A new object identity loads and resets. */
|
|
69
|
+
schema: ReportSchema | undefined;
|
|
70
|
+
/** The host's configured quario instance; `plan()` drives the edit loop. */
|
|
71
|
+
instance: Quario | undefined;
|
|
72
|
+
/** The html target, from `html({ paths: true })`. Nothing else renders a
|
|
73
|
+
* fragment the editor can map to the schema. */
|
|
74
|
+
target: Target<"html", Promise<string>> | undefined;
|
|
75
|
+
/** Functions callable from the document's expressions. */
|
|
76
|
+
functions: Record<string, (...args: never[]) => unknown> | undefined;
|
|
77
|
+
/** The sample data the preview renders on. */
|
|
78
|
+
data: unknown;
|
|
79
|
+
/** Sheet geometry — the same values a host passes to `pdf({ page })`. */
|
|
80
|
+
page: EditorPage | undefined;
|
|
81
|
+
/** Paints the chrome only. Unset is `"light"`; `"auto"` follows the OS. */
|
|
82
|
+
colorScheme: "light" | "dark" | "auto" | undefined;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Settles when the newest render settles: `true` when a fragment reached
|
|
86
|
+
* the sheet, `false` when it failed or there was nothing to render. Never
|
|
87
|
+
* rejects.
|
|
88
|
+
*/
|
|
89
|
+
get renderComplete(): Promise<boolean>;
|
|
90
|
+
|
|
91
|
+
addEventListener<K extends keyof QuarioEditorEventMap>(
|
|
92
|
+
type: K,
|
|
93
|
+
listener: (this: QuarioEditor, ev: QuarioEditorEventMap[K]) => void,
|
|
94
|
+
options?: boolean | AddEventListenerOptions,
|
|
95
|
+
): void;
|
|
96
|
+
addEventListener(
|
|
97
|
+
type: string,
|
|
98
|
+
listener: EventListenerOrEventListenerObject,
|
|
99
|
+
options?: boolean | AddEventListenerOptions,
|
|
100
|
+
): void;
|
|
101
|
+
removeEventListener<K extends keyof QuarioEditorEventMap>(
|
|
102
|
+
type: K,
|
|
103
|
+
listener: (this: QuarioEditor, ev: QuarioEditorEventMap[K]) => void,
|
|
104
|
+
options?: boolean | EventListenerOptions,
|
|
105
|
+
): void;
|
|
106
|
+
removeEventListener(
|
|
107
|
+
type: string,
|
|
108
|
+
listener: EventListenerOrEventListenerObject,
|
|
109
|
+
options?: boolean | EventListenerOptions,
|
|
110
|
+
): void;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface QuarioEditorEventMap {
|
|
114
|
+
change: CustomEvent<EditorChangeDetail>;
|
|
115
|
+
error: CustomEvent<EditorErrorDetail>;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** The tag `@quario/editor/register` defines the element under. */
|
|
119
|
+
export const TAG: "quario-editor";
|