@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/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";