typewright 0.2.1

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.
Files changed (40) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +168 -0
  3. package/SPEC.md +327 -0
  4. package/dist/chunk-CZQO7TTL.js +1533 -0
  5. package/dist/chunk-CZQO7TTL.js.map +1 -0
  6. package/dist/chunk-KNEKNZXK.js +286 -0
  7. package/dist/chunk-KNEKNZXK.js.map +1 -0
  8. package/dist/chunk-M6IVEMXO.js +1398 -0
  9. package/dist/chunk-M6IVEMXO.js.map +1 -0
  10. package/dist/chunk-NJ7PJKHN.js +652 -0
  11. package/dist/chunk-NJ7PJKHN.js.map +1 -0
  12. package/dist/commands-Z3ndUSza.d.cts +221 -0
  13. package/dist/commands-Z3ndUSza.d.ts +221 -0
  14. package/dist/core/index.cjs +2952 -0
  15. package/dist/core/index.cjs.map +1 -0
  16. package/dist/core/index.d.cts +410 -0
  17. package/dist/core/index.d.ts +410 -0
  18. package/dist/core/index.js +4 -0
  19. package/dist/core/index.js.map +1 -0
  20. package/dist/mdx/index.cjs +662 -0
  21. package/dist/mdx/index.cjs.map +1 -0
  22. package/dist/mdx/index.d.cts +252 -0
  23. package/dist/mdx/index.d.ts +252 -0
  24. package/dist/mdx/index.js +3 -0
  25. package/dist/mdx/index.js.map +1 -0
  26. package/dist/react/index.cjs +7439 -0
  27. package/dist/react/index.cjs.map +1 -0
  28. package/dist/react/index.d.cts +140 -0
  29. package/dist/react/index.d.ts +140 -0
  30. package/dist/react/index.js +3644 -0
  31. package/dist/react/index.js.map +1 -0
  32. package/dist/streaming/index.cjs +1494 -0
  33. package/dist/streaming/index.cjs.map +1 -0
  34. package/dist/streaming/index.d.cts +64 -0
  35. package/dist/streaming/index.d.ts +64 -0
  36. package/dist/streaming/index.js +4 -0
  37. package/dist/streaming/index.js.map +1 -0
  38. package/dist/types-CX1GOx0Y.d.cts +319 -0
  39. package/dist/types-CX1GOx0Y.d.ts +319 -0
  40. package/package.json +128 -0
@@ -0,0 +1,140 @@
1
+ import * as React from 'react';
2
+ import { E as EditorConfig, a as EditorEvents, h as EditorMode, A as AnticipationOptions, k as MdxTransform, e as ComponentMap, S as SandboxOptions } from '../types-CX1GOx0Y.cjs';
3
+ export { C as CommentReply, c as CommentThread, d as CommentsOptions, D as DocChange, f as DocPosition, g as DocRange, b as DocSelection, i as Extensions, F as FoldingOptions, G as GfmFeatures, K as KeymapOptions, M as MathOptions, j as MdxOptions, l as MermaidOptions, P as PresencePeer, m as SettingsCommand, n as SettingsOptions, o as StreamController, p as StreamOptions, q as SyntaxHighlightOptions, T as ThemeOptions } from '../types-CX1GOx0Y.cjs';
4
+ import { f as Command, B as Block } from '../commands-Z3ndUSza.cjs';
5
+
6
+ /** Imperative handle exposed via a ref on `<TypewrightEditor>`. */
7
+ interface TypewrightEditorHandle {
8
+ /** Apply a formatting command to the currently-focused editing surface. */
9
+ applyCommand: (command: Command) => void;
10
+ /** Switch the editor mode; also fires `onModeChange`. */
11
+ setMode: (mode: EditorMode) => void;
12
+ }
13
+ /**
14
+ * Typewright — drop-in Markdown + MDX editor React component.
15
+ *
16
+ * v1 engine (real, tested): the string is the source of truth; rendering goes
17
+ * through the sanitizing renderer (render.ts escapes text, guards URLs, and
18
+ * never emits raw HTML/MDX), so the `dangerouslySetInnerHTML` below is safe.
19
+ *
20
+ * Modes:
21
+ * - `edit` raw Markdown source (textarea) with standard shortcuts
22
+ * - `unified` live preview; click a block to reveal + edit its Markdown source
23
+ * - `preview` fully rendered
24
+ * - `read` fully rendered, no editing affordances
25
+ *
26
+ * Deferred to later phases (SPEC.md): character-level inline marker reveal,
27
+ * custom virtualization/IME, MDX JSX sandbox execution, Mermaid, in-place table
28
+ * grid, comments/collaboration. These are represented in the design demo.
29
+ */
30
+ interface TypewrightEditorProps extends EditorConfig, EditorEvents {
31
+ /** Controlled Markdown value. */
32
+ value?: string;
33
+ /** Uncontrolled initial value. */
34
+ defaultValue?: string;
35
+ className?: string;
36
+ style?: React.CSSProperties;
37
+ }
38
+ declare function useInjectStyles(): void;
39
+ declare const TypewrightEditor: React.ForwardRefExoticComponent<TypewrightEditorProps & React.RefAttributes<TypewrightEditorHandle>>;
40
+
41
+ /**
42
+ * Streaming preview — renders an AI/LLM token stream incrementally while
43
+ * anticipating incomplete formatting (SPEC.md §8). Committed blocks are
44
+ * reconciled in place (stable, no flicker); new blocks animate in and a block
45
+ * whose type changes (e.g. skeleton → resolved) re-animates. The HTML comes
46
+ * from the sanitizing renderer + class-only pending markup, so it is safe.
47
+ *
48
+ * Drive it with an updating `text` prop, or hand it a `stream` (async iterable
49
+ * or ReadableStream of string chunks).
50
+ */
51
+ interface StreamingPreviewProps {
52
+ /** Controlled accumulated text. */
53
+ text?: string;
54
+ /** A stream of chunks to consume (alternative to `text`). */
55
+ stream?: AsyncIterable<string> | ReadableStream<string>;
56
+ /** Which incomplete constructs to optimistically render. */
57
+ anticipate?: boolean | AnticipationOptions;
58
+ /**
59
+ * Reveal characters smoothly rather than in raw chunk jumps (only affects the
60
+ * `stream` path — the controlled `text` prop is the host's to pace). `true`
61
+ * uses a default rate; `{ charsPerSecond }` sets it. Mirrors `StreamOptions.smooth`.
62
+ */
63
+ smooth?: boolean | {
64
+ charsPerSecond: number;
65
+ };
66
+ /** Label shown inside the skeleton of a component whose props are still streaming. */
67
+ componentFallback?: string;
68
+ className?: string;
69
+ style?: React.CSSProperties;
70
+ }
71
+ declare function StreamingPreview(props: StreamingPreviewProps): React.ReactElement;
72
+
73
+ /**
74
+ * SandboxIsland — one executable widget island rendered *as the sandbox iframe*
75
+ * (Phase D4 / E1, SPEC.md §7/§11). The compiled MDX / Mermaid output stays
76
+ * **inside** the opaque-origin `<iframe sandbox="allow-scripts">` created by
77
+ * {@link createSandbox}; the host tree never `innerHTML`s the untrusted output
78
+ * (invariant K-3). The iframe itself is the widget — this component only mounts
79
+ * the sandbox into a container `<div>` it owns, un-hides + sizes the iframe once
80
+ * the sandbox reports a height, and shows an inline error card on failure.
81
+ *
82
+ * Lifecycle:
83
+ * - **create/reuse** — a single sandbox is created on mount (in a container ref
84
+ * passed as {@link createSandbox}'s `container`) and reused across `code`
85
+ * edits; it is recreated only when the engine identity changes (a Mermaid
86
+ * engine or CSP is baked into the sandbox document at creation).
87
+ * - **evaluate** — DEBOUNCED ~250 ms after `code` (or the MDX transform/
88
+ * components) change: `mdx` → `resolveTransform(transform)(code)` then
89
+ * `sandbox.evaluate(js, {components})`; `mermaid` → `sandbox.renderMermaid(code)`.
90
+ * - **destroy** — the sandbox is torn down on unmount.
91
+ *
92
+ * Failure handling (invariant K-6 — editing must never break): a transform
93
+ * throw, an `evaluate`/`renderMermaid` error result, or any unexpected throw is
94
+ * caught and surfaced as an inline `.tw-island-error` card (the message is
95
+ * rendered as escaped text by React, never as HTML). The component itself never
96
+ * throws during render.
97
+ *
98
+ * With no MDX transform configured the island falls back to the escaped source
99
+ * in a `<pre>` (the "no transform" case) — the same safe form the renderer uses.
100
+ */
101
+ interface SandboxIslandProps {
102
+ /** `mdx` runs a compiled MDX module; `mermaid` renders a diagram. */
103
+ kind: 'mdx' | 'mermaid';
104
+ /** Raw `mdxFlow` source (mdx), or the Mermaid diagram source (mermaid). */
105
+ code: string;
106
+ /** How to compile the MDX source to runnable JS (mdx only). */
107
+ transform?: MdxTransform;
108
+ /** Components made available to the compiled module (mdx only). */
109
+ components?: ComponentMap;
110
+ /** Sandbox options (opaque-origin iframe; `allowSameOrigin` is type-forbidden). */
111
+ sandbox?: SandboxOptions;
112
+ /** Resolved Mermaid engine JavaScript *source*, inlined into the sandbox (mermaid only). */
113
+ mermaidEngine?: string;
114
+ /** Colour scheme hint applied to the iframe + error card. */
115
+ theme?: 'light' | 'dark';
116
+ }
117
+ declare function SandboxIslandBase(props: SandboxIslandProps): React.ReactElement;
118
+ /**
119
+ * Memoized so an island only re-compiles/re-renders when its own `code`/config
120
+ * changes — a keystroke in a *different* block leaves every island untouched.
121
+ */
122
+ declare const SandboxIsland: React.MemoExoticComponent<typeof SandboxIslandBase>;
123
+
124
+ interface CaretRevealBlockProps {
125
+ /** The parsed block whose offsets index into {@link source}. */
126
+ block: Block;
127
+ /** Full document source (the single source of truth). */
128
+ source: string;
129
+ /** Emit a scoped splice: `source[from..to]` becomes `insert`. */
130
+ onChange: (change: {
131
+ from: number;
132
+ to: number;
133
+ insert: string;
134
+ }) => void;
135
+ readOnly?: boolean;
136
+ }
137
+ declare function CaretRevealBlock(props: CaretRevealBlockProps): React.ReactElement;
138
+ declare const CARET_REVEAL_CSS = "\n.tw-caret-block{white-space:pre-wrap;overflow-wrap:break-word;outline:none;cursor:text;border-radius:6px;padding:1px 4px;margin-left:-4px;transition:background .15s}\n.tw-mode-unified .tw-caret-block:hover{background:var(--tw-accent-soft)}\n.tw-caret-block:focus-visible{outline:2px solid var(--tw-accent);outline-offset:2px}\n.tw-caret-block.tw-cr-heading{font-weight:680;letter-spacing:-.02em;line-height:1.25}\n.tw-caret-block.tw-cr-h1{font-size:1.8em} .tw-caret-block.tw-cr-h2{font-size:1.45em} .tw-caret-block.tw-cr-h3{font-size:1.2em} .tw-caret-block.tw-cr-h4{font-size:1.05em} .tw-caret-block.tw-cr-h5{font-size:1em} .tw-caret-block.tw-cr-h6{font-size:.92em;color:var(--tw-muted)}\n.tw-caret-block.tw-cr-blockquote{border-left:3px solid var(--tw-line);padding-left:14px;color:var(--tw-muted)}\n.tw-caret-block.tw-cr-list{padding-left:6px}\n.tw-caret-block a{color:var(--tw-accent);text-decoration:none;border-bottom:1px solid var(--tw-accent-soft)}\n.tw-caret-block code{font-family:\"SF Mono\",ui-monospace,Menlo,monospace;font-size:.88em;background:var(--tw-chip);border:1px solid var(--tw-line);border-radius:5px;padding:1px 5px}\n.tw-caret-block .tw-cr-img{color:var(--tw-muted);font-style:italic}\n.tw-caret-block .tw-fnref{font-size:.82em;color:var(--tw-accent)}\n/* Revealed marker: subtle, monospace, \"you are editing raw syntax\". */\n.tw-syntax{font-family:\"SF Mono\",ui-monospace,Menlo,monospace;color:var(--tw-faint);opacity:.85;font-weight:400;font-style:normal}\n/* Hidden marker: collapsed out of layout, but its source chars stay in the DOM\n (and in this component's offset mapping) \u2014 never removed from the string. */\n.tw-syntax--hidden{display:none}\n@media (prefers-reduced-motion: reduce){ .tw-caret-block{transition:none} }\n";
139
+
140
+ export { AnticipationOptions, CARET_REVEAL_CSS, CaretRevealBlock, type CaretRevealBlockProps, ComponentMap, EditorConfig, EditorEvents, EditorMode, MdxTransform, SandboxIsland, type SandboxIslandProps, SandboxOptions, StreamingPreview, type StreamingPreviewProps, TypewrightEditor, type TypewrightEditorHandle, type TypewrightEditorProps, useInjectStyles };
@@ -0,0 +1,140 @@
1
+ import * as React from 'react';
2
+ import { E as EditorConfig, a as EditorEvents, h as EditorMode, A as AnticipationOptions, k as MdxTransform, e as ComponentMap, S as SandboxOptions } from '../types-CX1GOx0Y.js';
3
+ export { C as CommentReply, c as CommentThread, d as CommentsOptions, D as DocChange, f as DocPosition, g as DocRange, b as DocSelection, i as Extensions, F as FoldingOptions, G as GfmFeatures, K as KeymapOptions, M as MathOptions, j as MdxOptions, l as MermaidOptions, P as PresencePeer, m as SettingsCommand, n as SettingsOptions, o as StreamController, p as StreamOptions, q as SyntaxHighlightOptions, T as ThemeOptions } from '../types-CX1GOx0Y.js';
4
+ import { f as Command, B as Block } from '../commands-Z3ndUSza.js';
5
+
6
+ /** Imperative handle exposed via a ref on `<TypewrightEditor>`. */
7
+ interface TypewrightEditorHandle {
8
+ /** Apply a formatting command to the currently-focused editing surface. */
9
+ applyCommand: (command: Command) => void;
10
+ /** Switch the editor mode; also fires `onModeChange`. */
11
+ setMode: (mode: EditorMode) => void;
12
+ }
13
+ /**
14
+ * Typewright — drop-in Markdown + MDX editor React component.
15
+ *
16
+ * v1 engine (real, tested): the string is the source of truth; rendering goes
17
+ * through the sanitizing renderer (render.ts escapes text, guards URLs, and
18
+ * never emits raw HTML/MDX), so the `dangerouslySetInnerHTML` below is safe.
19
+ *
20
+ * Modes:
21
+ * - `edit` raw Markdown source (textarea) with standard shortcuts
22
+ * - `unified` live preview; click a block to reveal + edit its Markdown source
23
+ * - `preview` fully rendered
24
+ * - `read` fully rendered, no editing affordances
25
+ *
26
+ * Deferred to later phases (SPEC.md): character-level inline marker reveal,
27
+ * custom virtualization/IME, MDX JSX sandbox execution, Mermaid, in-place table
28
+ * grid, comments/collaboration. These are represented in the design demo.
29
+ */
30
+ interface TypewrightEditorProps extends EditorConfig, EditorEvents {
31
+ /** Controlled Markdown value. */
32
+ value?: string;
33
+ /** Uncontrolled initial value. */
34
+ defaultValue?: string;
35
+ className?: string;
36
+ style?: React.CSSProperties;
37
+ }
38
+ declare function useInjectStyles(): void;
39
+ declare const TypewrightEditor: React.ForwardRefExoticComponent<TypewrightEditorProps & React.RefAttributes<TypewrightEditorHandle>>;
40
+
41
+ /**
42
+ * Streaming preview — renders an AI/LLM token stream incrementally while
43
+ * anticipating incomplete formatting (SPEC.md §8). Committed blocks are
44
+ * reconciled in place (stable, no flicker); new blocks animate in and a block
45
+ * whose type changes (e.g. skeleton → resolved) re-animates. The HTML comes
46
+ * from the sanitizing renderer + class-only pending markup, so it is safe.
47
+ *
48
+ * Drive it with an updating `text` prop, or hand it a `stream` (async iterable
49
+ * or ReadableStream of string chunks).
50
+ */
51
+ interface StreamingPreviewProps {
52
+ /** Controlled accumulated text. */
53
+ text?: string;
54
+ /** A stream of chunks to consume (alternative to `text`). */
55
+ stream?: AsyncIterable<string> | ReadableStream<string>;
56
+ /** Which incomplete constructs to optimistically render. */
57
+ anticipate?: boolean | AnticipationOptions;
58
+ /**
59
+ * Reveal characters smoothly rather than in raw chunk jumps (only affects the
60
+ * `stream` path — the controlled `text` prop is the host's to pace). `true`
61
+ * uses a default rate; `{ charsPerSecond }` sets it. Mirrors `StreamOptions.smooth`.
62
+ */
63
+ smooth?: boolean | {
64
+ charsPerSecond: number;
65
+ };
66
+ /** Label shown inside the skeleton of a component whose props are still streaming. */
67
+ componentFallback?: string;
68
+ className?: string;
69
+ style?: React.CSSProperties;
70
+ }
71
+ declare function StreamingPreview(props: StreamingPreviewProps): React.ReactElement;
72
+
73
+ /**
74
+ * SandboxIsland — one executable widget island rendered *as the sandbox iframe*
75
+ * (Phase D4 / E1, SPEC.md §7/§11). The compiled MDX / Mermaid output stays
76
+ * **inside** the opaque-origin `<iframe sandbox="allow-scripts">` created by
77
+ * {@link createSandbox}; the host tree never `innerHTML`s the untrusted output
78
+ * (invariant K-3). The iframe itself is the widget — this component only mounts
79
+ * the sandbox into a container `<div>` it owns, un-hides + sizes the iframe once
80
+ * the sandbox reports a height, and shows an inline error card on failure.
81
+ *
82
+ * Lifecycle:
83
+ * - **create/reuse** — a single sandbox is created on mount (in a container ref
84
+ * passed as {@link createSandbox}'s `container`) and reused across `code`
85
+ * edits; it is recreated only when the engine identity changes (a Mermaid
86
+ * engine or CSP is baked into the sandbox document at creation).
87
+ * - **evaluate** — DEBOUNCED ~250 ms after `code` (or the MDX transform/
88
+ * components) change: `mdx` → `resolveTransform(transform)(code)` then
89
+ * `sandbox.evaluate(js, {components})`; `mermaid` → `sandbox.renderMermaid(code)`.
90
+ * - **destroy** — the sandbox is torn down on unmount.
91
+ *
92
+ * Failure handling (invariant K-6 — editing must never break): a transform
93
+ * throw, an `evaluate`/`renderMermaid` error result, or any unexpected throw is
94
+ * caught and surfaced as an inline `.tw-island-error` card (the message is
95
+ * rendered as escaped text by React, never as HTML). The component itself never
96
+ * throws during render.
97
+ *
98
+ * With no MDX transform configured the island falls back to the escaped source
99
+ * in a `<pre>` (the "no transform" case) — the same safe form the renderer uses.
100
+ */
101
+ interface SandboxIslandProps {
102
+ /** `mdx` runs a compiled MDX module; `mermaid` renders a diagram. */
103
+ kind: 'mdx' | 'mermaid';
104
+ /** Raw `mdxFlow` source (mdx), or the Mermaid diagram source (mermaid). */
105
+ code: string;
106
+ /** How to compile the MDX source to runnable JS (mdx only). */
107
+ transform?: MdxTransform;
108
+ /** Components made available to the compiled module (mdx only). */
109
+ components?: ComponentMap;
110
+ /** Sandbox options (opaque-origin iframe; `allowSameOrigin` is type-forbidden). */
111
+ sandbox?: SandboxOptions;
112
+ /** Resolved Mermaid engine JavaScript *source*, inlined into the sandbox (mermaid only). */
113
+ mermaidEngine?: string;
114
+ /** Colour scheme hint applied to the iframe + error card. */
115
+ theme?: 'light' | 'dark';
116
+ }
117
+ declare function SandboxIslandBase(props: SandboxIslandProps): React.ReactElement;
118
+ /**
119
+ * Memoized so an island only re-compiles/re-renders when its own `code`/config
120
+ * changes — a keystroke in a *different* block leaves every island untouched.
121
+ */
122
+ declare const SandboxIsland: React.MemoExoticComponent<typeof SandboxIslandBase>;
123
+
124
+ interface CaretRevealBlockProps {
125
+ /** The parsed block whose offsets index into {@link source}. */
126
+ block: Block;
127
+ /** Full document source (the single source of truth). */
128
+ source: string;
129
+ /** Emit a scoped splice: `source[from..to]` becomes `insert`. */
130
+ onChange: (change: {
131
+ from: number;
132
+ to: number;
133
+ insert: string;
134
+ }) => void;
135
+ readOnly?: boolean;
136
+ }
137
+ declare function CaretRevealBlock(props: CaretRevealBlockProps): React.ReactElement;
138
+ declare const CARET_REVEAL_CSS = "\n.tw-caret-block{white-space:pre-wrap;overflow-wrap:break-word;outline:none;cursor:text;border-radius:6px;padding:1px 4px;margin-left:-4px;transition:background .15s}\n.tw-mode-unified .tw-caret-block:hover{background:var(--tw-accent-soft)}\n.tw-caret-block:focus-visible{outline:2px solid var(--tw-accent);outline-offset:2px}\n.tw-caret-block.tw-cr-heading{font-weight:680;letter-spacing:-.02em;line-height:1.25}\n.tw-caret-block.tw-cr-h1{font-size:1.8em} .tw-caret-block.tw-cr-h2{font-size:1.45em} .tw-caret-block.tw-cr-h3{font-size:1.2em} .tw-caret-block.tw-cr-h4{font-size:1.05em} .tw-caret-block.tw-cr-h5{font-size:1em} .tw-caret-block.tw-cr-h6{font-size:.92em;color:var(--tw-muted)}\n.tw-caret-block.tw-cr-blockquote{border-left:3px solid var(--tw-line);padding-left:14px;color:var(--tw-muted)}\n.tw-caret-block.tw-cr-list{padding-left:6px}\n.tw-caret-block a{color:var(--tw-accent);text-decoration:none;border-bottom:1px solid var(--tw-accent-soft)}\n.tw-caret-block code{font-family:\"SF Mono\",ui-monospace,Menlo,monospace;font-size:.88em;background:var(--tw-chip);border:1px solid var(--tw-line);border-radius:5px;padding:1px 5px}\n.tw-caret-block .tw-cr-img{color:var(--tw-muted);font-style:italic}\n.tw-caret-block .tw-fnref{font-size:.82em;color:var(--tw-accent)}\n/* Revealed marker: subtle, monospace, \"you are editing raw syntax\". */\n.tw-syntax{font-family:\"SF Mono\",ui-monospace,Menlo,monospace;color:var(--tw-faint);opacity:.85;font-weight:400;font-style:normal}\n/* Hidden marker: collapsed out of layout, but its source chars stay in the DOM\n (and in this component's offset mapping) \u2014 never removed from the string. */\n.tw-syntax--hidden{display:none}\n@media (prefers-reduced-motion: reduce){ .tw-caret-block{transition:none} }\n";
139
+
140
+ export { AnticipationOptions, CARET_REVEAL_CSS, CaretRevealBlock, type CaretRevealBlockProps, ComponentMap, EditorConfig, EditorEvents, EditorMode, MdxTransform, SandboxIsland, type SandboxIslandProps, SandboxOptions, StreamingPreview, type StreamingPreviewProps, TypewrightEditor, type TypewrightEditorHandle, type TypewrightEditorProps, useInjectStyles };