quoin-editor 0.1.1 → 0.3.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 +246 -48
- package/dist/index.cjs +80 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +125 -16
- package/dist/index.d.ts +125 -16
- package/dist/index.js +75 -45
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -42,18 +42,11 @@ type BlockEditorProps<D = Record<string, unknown>> = {
|
|
|
42
42
|
onDone?: () => void;
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
-
/**
|
|
46
|
-
type
|
|
45
|
+
/** The fields every block definition carries, whatever it can do with its data. */
|
|
46
|
+
type BlockDefinitionCommon<D extends object> = {
|
|
47
47
|
type: string;
|
|
48
48
|
label: string;
|
|
49
49
|
icon: LucideIcon;
|
|
50
|
-
editor: ComponentType<BlockEditorProps<D>>;
|
|
51
|
-
/**
|
|
52
|
-
* What the block shows when it is not being edited. Optional so a host can register an
|
|
53
|
-
* edit-only block type, and overridable so a host can supply rich rendering (a full
|
|
54
|
-
* markdown pipeline, a chart) without Quoin depending on one.
|
|
55
|
-
*/
|
|
56
|
-
preview?: ComponentType<BlockPreviewProps<D>>;
|
|
57
50
|
/**
|
|
58
51
|
* Called when a new block of this type is inserted, to seed its data.
|
|
59
52
|
* `NoInfer` keeps `D` inferred from `editor` and `preview` alone, so the seed is checked
|
|
@@ -69,6 +62,31 @@ type BlockDefinition<D extends object = Record<string, unknown>> = {
|
|
|
69
62
|
*/
|
|
70
63
|
alwaysEditing?: boolean;
|
|
71
64
|
};
|
|
65
|
+
/**
|
|
66
|
+
* Describes one block type: how to label it, how to draw it at rest, how to edit it.
|
|
67
|
+
*
|
|
68
|
+
* Supply `editor`, `preview`, or both, and the canvas does the rest. A definition with no
|
|
69
|
+
* `preview` is edit-only: a read-only canvas has nothing to draw for it but its label.
|
|
70
|
+
* A definition with no `editor` can never be edited in the canvas, which is what a block
|
|
71
|
+
* whose content belongs to a server-side record wants; the card offers no edit affordance
|
|
72
|
+
* for it and a click goes through to whatever the preview itself renders.
|
|
73
|
+
*
|
|
74
|
+
* Omitting both is a type error, because such a block would only ever draw its own label.
|
|
75
|
+
*/
|
|
76
|
+
type BlockDefinition<D extends object = Record<string, unknown>> = (BlockDefinitionCommon<D> & {
|
|
77
|
+
editor: ComponentType<BlockEditorProps<D>>;
|
|
78
|
+
/**
|
|
79
|
+
* What the block shows when it is not being edited. Optional so a host can register an
|
|
80
|
+
* edit-only block type, and overridable so a host can supply rich rendering (a full
|
|
81
|
+
* markdown pipeline, a chart) without Quoin depending on one.
|
|
82
|
+
*/
|
|
83
|
+
preview?: ComponentType<BlockPreviewProps<D>>;
|
|
84
|
+
}) | (BlockDefinitionCommon<D> & {
|
|
85
|
+
/** Omitted: this block is never editable in the canvas. */
|
|
86
|
+
editor?: undefined;
|
|
87
|
+
/** Required here, because it is the only thing that can draw the block. */
|
|
88
|
+
preview: ComponentType<BlockPreviewProps<D>>;
|
|
89
|
+
});
|
|
72
90
|
/** A definition with its data type erased, so definitions of different shapes compose in one array. */
|
|
73
91
|
type AnyBlockDefinition = BlockDefinition<Record<string, unknown>>;
|
|
74
92
|
/**
|
|
@@ -77,8 +95,11 @@ type AnyBlockDefinition = BlockDefinition<Record<string, unknown>>;
|
|
|
77
95
|
* on `editor`, so without it an array of differently-shaped definitions will not typecheck.
|
|
78
96
|
* `initialData` is checked against the editor's data type. That relies on `NoInfer`, so
|
|
79
97
|
* TypeScript 5.4 or later is required.
|
|
98
|
+
*
|
|
99
|
+
* `D` defaults to `Record<string, unknown>`, so a definition whose components take no
|
|
100
|
+
* annotation still gets a usable `data` rather than a bare `object`.
|
|
80
101
|
*/
|
|
81
|
-
declare function defineBlock<D extends object
|
|
102
|
+
declare function defineBlock<D extends object = Record<string, unknown>>(definition: BlockDefinition<D>): AnyBlockDefinition;
|
|
82
103
|
/** The definition for a type, or undefined; the last registration of a type wins, so a host can override a core block. */
|
|
83
104
|
declare function blockByType(definitions: AnyBlockDefinition[], type: string): AnyBlockDefinition | undefined;
|
|
84
105
|
/** The definitions offered in the slash palette, in registration order, one per type, with the last registration of a type winning. */
|
|
@@ -102,6 +123,17 @@ type BlockCanvasProps = {
|
|
|
102
123
|
*/
|
|
103
124
|
blocks: QuoinBlock[];
|
|
104
125
|
onChange: (blocks: QuoinBlock[]) => void;
|
|
126
|
+
/**
|
|
127
|
+
* Called when a block is removed through its actions menu, with the block and the index it held.
|
|
128
|
+
* It runs just after the `onChange` that reports the document without it, so a host acting on the
|
|
129
|
+
* deletion is already looking at the new array. Restore the block by supplying a `blocks` array
|
|
130
|
+
* with it spliced back at that index, the same way any other document arrives.
|
|
131
|
+
*
|
|
132
|
+
* Restore it on a later tick or a later interaction, such as the click of an Undo toast. A
|
|
133
|
+
* restore applied synchronously inside this callback batches with the echo of the deletion, so
|
|
134
|
+
* what arrives is structurally equal to the document last supplied and is ignored.
|
|
135
|
+
*/
|
|
136
|
+
onDelete?: (block: QuoinBlock, index: number) => void;
|
|
105
137
|
/** Defaults to the five core block types. Pass `[...coreBlocks, yours]` to extend them. */
|
|
106
138
|
blockTypes?: AnyBlockDefinition[];
|
|
107
139
|
upload?: UploadFn;
|
|
@@ -116,11 +148,87 @@ type BlockCanvasProps = {
|
|
|
116
148
|
'aria-label'?: string;
|
|
117
149
|
};
|
|
118
150
|
/** The editor: renders `blocks`, reports every edit through `onChange`, and accepts a new `blocks` array from outside at any time. */
|
|
119
|
-
declare function BlockCanvas({ blocks, onChange, blockTypes, upload, resolveAssetUrl, onError, readOnly, className, id, 'aria-label': ariaLabel, }: BlockCanvasProps): React.JSX.Element;
|
|
151
|
+
declare function BlockCanvas({ blocks, onChange, onDelete, blockTypes, upload, resolveAssetUrl, onError, readOnly, className, id, 'aria-label': ariaLabel, }: BlockCanvasProps): React.JSX.Element;
|
|
120
152
|
|
|
121
153
|
/** The block types Quoin ships with. Spread them alongside your own definitions. */
|
|
122
154
|
declare const coreBlocks: AnyBlockDefinition[];
|
|
123
155
|
|
|
156
|
+
/**
|
|
157
|
+
* The `data` shape each core block keeps its content under. A host that persists blocks
|
|
158
|
+
* itself reads and writes these, so they are part of the public surface rather than an
|
|
159
|
+
* implementation detail. `core-data.test.tsx` holds every one of them against the editor
|
|
160
|
+
* that writes it and the seed it starts from.
|
|
161
|
+
*
|
|
162
|
+
* Every field is declared because something writes it. The optional ones are written
|
|
163
|
+
* later than the block's first save: an image's `caption` when the author types one, its
|
|
164
|
+
* `width` and `height` once the uploaded bytes have been measured, a file's `size` when
|
|
165
|
+
* the upload reports it.
|
|
166
|
+
*/
|
|
167
|
+
/** `MARKDOWN`. The source text, not rendered HTML: Quoin stores and edits markdown. */
|
|
168
|
+
type MarkdownBlockData = {
|
|
169
|
+
markdown: string;
|
|
170
|
+
};
|
|
171
|
+
/** `CALLOUT`. The prose is under `body`, not `text`. */
|
|
172
|
+
type CalloutBlockData = {
|
|
173
|
+
tone: string;
|
|
174
|
+
body: string;
|
|
175
|
+
};
|
|
176
|
+
/** `CODE`. `language` is a free string, written through as the author typed it. */
|
|
177
|
+
type CodeBlockData = {
|
|
178
|
+
language: string;
|
|
179
|
+
code: string;
|
|
180
|
+
};
|
|
181
|
+
/** `IMAGE`. `storageKey` names the uploaded file; the host's `resolveAssetUrl` turns it into a URL. */
|
|
182
|
+
type ImageBlockData = {
|
|
183
|
+
storageKey: string;
|
|
184
|
+
alt: string;
|
|
185
|
+
caption?: string;
|
|
186
|
+
width?: number;
|
|
187
|
+
height?: number;
|
|
188
|
+
};
|
|
189
|
+
/** `FILE`. `storageKey` names the uploaded file; `filename` is what the author picked. */
|
|
190
|
+
type FileBlockData = {
|
|
191
|
+
storageKey: string;
|
|
192
|
+
filename: string;
|
|
193
|
+
size?: number;
|
|
194
|
+
};
|
|
195
|
+
/** Maps each core block's `type` string to its data shape. */
|
|
196
|
+
type CoreBlockData = {
|
|
197
|
+
MARKDOWN: MarkdownBlockData;
|
|
198
|
+
CALLOUT: CalloutBlockData;
|
|
199
|
+
CODE: CodeBlockData;
|
|
200
|
+
IMAGE: ImageBlockData;
|
|
201
|
+
FILE: FileBlockData;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
/** Props for `UploadField`; the upload function itself comes from the canvas, not from here. */
|
|
205
|
+
type UploadFieldProps = {
|
|
206
|
+
/** Names what the file is for, and is passed to the host's `upload` as its second argument. */
|
|
207
|
+
category: string;
|
|
208
|
+
/** Labels the control for both the pointer and assistive technology. */
|
|
209
|
+
label: string;
|
|
210
|
+
/** An `accept` attribute for the file input, such as `'image/*'` or `'.pdf'`. */
|
|
211
|
+
accept?: string;
|
|
212
|
+
/** Called once the upload resolves. Throwing from it is reported through the canvas `onError`. */
|
|
213
|
+
onUploaded: (result: UploadResult) => void;
|
|
214
|
+
};
|
|
215
|
+
/** A file picker wired to the canvas `upload` function, with its own busy state and inline error. */
|
|
216
|
+
declare function UploadField({ category, label, accept, onUploaded }: UploadFieldProps): React.JSX.Element;
|
|
217
|
+
|
|
218
|
+
/** Props for `FilePickerButton`. */
|
|
219
|
+
type FilePickerButtonProps = {
|
|
220
|
+
/** Labels the button and the file input behind it. */
|
|
221
|
+
label: string;
|
|
222
|
+
/** An `accept` attribute for the file input, such as `'image/*'` or `'.pdf'`. */
|
|
223
|
+
accept?: string;
|
|
224
|
+
/** Greys the button out and disables the input behind it. */
|
|
225
|
+
disabled?: boolean;
|
|
226
|
+
/** Called with the chosen file, and again if the same file is picked after a failure. */
|
|
227
|
+
onPick: (file: File) => void;
|
|
228
|
+
};
|
|
229
|
+
/** A button that opens the file picker and hands back the chosen file, performing no upload of its own. */
|
|
230
|
+
declare function FilePickerButton({ label, accept, disabled, onPick }: FilePickerButtonProps): React.JSX.Element;
|
|
231
|
+
|
|
124
232
|
/** The resolved canvas configuration every block editor reads through `useQuoin`. */
|
|
125
233
|
type QuoinConfig = {
|
|
126
234
|
blockTypes: AnyBlockDefinition[];
|
|
@@ -160,15 +268,16 @@ declare function useBlockList(initial: QuoinBlock[]): BlockList;
|
|
|
160
268
|
|
|
161
269
|
/** Where a debounced save stands, for a "Saving..." or "Saved" indicator. */
|
|
162
270
|
type AutosaveStatus = 'idle' | 'saving' | 'saved' | 'retrying';
|
|
163
|
-
type SaveResult = {
|
|
164
|
-
ok?: boolean;
|
|
165
|
-
} | void;
|
|
166
271
|
/** What `useAutosave` tracks, how to build the payload, and how to persist it. */
|
|
167
272
|
type UseAutosaveInput<T> = {
|
|
168
273
|
/** The tracked fields. An edit to any of them marks dirty and restarts the debounce. */
|
|
169
274
|
deps: React.DependencyList;
|
|
170
275
|
build: () => T;
|
|
171
|
-
|
|
276
|
+
/**
|
|
277
|
+
* Persists the payload. Return anything: a mutation or a `fetch` that resolves to a body
|
|
278
|
+
* can be passed straight in. A save fails by rejecting, or by resolving to `{ ok: false }`.
|
|
279
|
+
*/
|
|
280
|
+
save: (payload: T) => unknown;
|
|
172
281
|
debounceMs?: number;
|
|
173
282
|
maxBackoffMs?: number;
|
|
174
283
|
};
|
|
@@ -279,4 +388,4 @@ declare function useMarkdownKeymap({ commit, onOpenPalette, }: {
|
|
|
279
388
|
onPaste: (event: React.ClipboardEvent<HTMLTextAreaElement>) => void;
|
|
280
389
|
};
|
|
281
390
|
|
|
282
|
-
export { type AnyBlockDefinition, type AutosaveStatus, BlockCanvas, type BlockCanvasProps, type BlockDefinition, type BlockEditorProps, type BlockList, type BlockPreviewProps, type CaretRect, type Edit, type InsertableCommand, type LinePrefix, type QuoinBlock, type QuoinConfig, type QuoinConfigInput, QuoinProvider, TEXT_COMMANDS, type TextCommand, type UndoToken, type UploadFn, type UploadResult, type UseAutosaveInput, type UseAutosaveResult, type WrapKind, applyEdit, blockByType, caretRect, continueList, coreBlocks, defineBlock, formatShortcut, indentList, insertCommand, lineAt, linkPaste, paletteBlocks, shouldOpenPalette, toggleLinePrefix, useAutoGrow, useAutosave, useBlockList, useMarkdownKeymap, useQuoin, wrapSelection };
|
|
391
|
+
export { type AnyBlockDefinition, type AutosaveStatus, BlockCanvas, type BlockCanvasProps, type BlockDefinition, type BlockEditorProps, type BlockList, type BlockPreviewProps, type CalloutBlockData, type CaretRect, type CodeBlockData, type CoreBlockData, type Edit, type FileBlockData, FilePickerButton, type FilePickerButtonProps, type ImageBlockData, type InsertableCommand, type LinePrefix, type MarkdownBlockData, type QuoinBlock, type QuoinConfig, type QuoinConfigInput, QuoinProvider, TEXT_COMMANDS, type TextCommand, type UndoToken, UploadField, type UploadFieldProps, type UploadFn, type UploadResult, type UseAutosaveInput, type UseAutosaveResult, type WrapKind, applyEdit, blockByType, caretRect, continueList, coreBlocks, defineBlock, formatShortcut, indentList, insertCommand, lineAt, linkPaste, paletteBlocks, shouldOpenPalette, toggleLinePrefix, useAutoGrow, useAutosave, useBlockList, useMarkdownKeymap, useQuoin, wrapSelection };
|
package/dist/index.d.ts
CHANGED
|
@@ -42,18 +42,11 @@ type BlockEditorProps<D = Record<string, unknown>> = {
|
|
|
42
42
|
onDone?: () => void;
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
-
/**
|
|
46
|
-
type
|
|
45
|
+
/** The fields every block definition carries, whatever it can do with its data. */
|
|
46
|
+
type BlockDefinitionCommon<D extends object> = {
|
|
47
47
|
type: string;
|
|
48
48
|
label: string;
|
|
49
49
|
icon: LucideIcon;
|
|
50
|
-
editor: ComponentType<BlockEditorProps<D>>;
|
|
51
|
-
/**
|
|
52
|
-
* What the block shows when it is not being edited. Optional so a host can register an
|
|
53
|
-
* edit-only block type, and overridable so a host can supply rich rendering (a full
|
|
54
|
-
* markdown pipeline, a chart) without Quoin depending on one.
|
|
55
|
-
*/
|
|
56
|
-
preview?: ComponentType<BlockPreviewProps<D>>;
|
|
57
50
|
/**
|
|
58
51
|
* Called when a new block of this type is inserted, to seed its data.
|
|
59
52
|
* `NoInfer` keeps `D` inferred from `editor` and `preview` alone, so the seed is checked
|
|
@@ -69,6 +62,31 @@ type BlockDefinition<D extends object = Record<string, unknown>> = {
|
|
|
69
62
|
*/
|
|
70
63
|
alwaysEditing?: boolean;
|
|
71
64
|
};
|
|
65
|
+
/**
|
|
66
|
+
* Describes one block type: how to label it, how to draw it at rest, how to edit it.
|
|
67
|
+
*
|
|
68
|
+
* Supply `editor`, `preview`, or both, and the canvas does the rest. A definition with no
|
|
69
|
+
* `preview` is edit-only: a read-only canvas has nothing to draw for it but its label.
|
|
70
|
+
* A definition with no `editor` can never be edited in the canvas, which is what a block
|
|
71
|
+
* whose content belongs to a server-side record wants; the card offers no edit affordance
|
|
72
|
+
* for it and a click goes through to whatever the preview itself renders.
|
|
73
|
+
*
|
|
74
|
+
* Omitting both is a type error, because such a block would only ever draw its own label.
|
|
75
|
+
*/
|
|
76
|
+
type BlockDefinition<D extends object = Record<string, unknown>> = (BlockDefinitionCommon<D> & {
|
|
77
|
+
editor: ComponentType<BlockEditorProps<D>>;
|
|
78
|
+
/**
|
|
79
|
+
* What the block shows when it is not being edited. Optional so a host can register an
|
|
80
|
+
* edit-only block type, and overridable so a host can supply rich rendering (a full
|
|
81
|
+
* markdown pipeline, a chart) without Quoin depending on one.
|
|
82
|
+
*/
|
|
83
|
+
preview?: ComponentType<BlockPreviewProps<D>>;
|
|
84
|
+
}) | (BlockDefinitionCommon<D> & {
|
|
85
|
+
/** Omitted: this block is never editable in the canvas. */
|
|
86
|
+
editor?: undefined;
|
|
87
|
+
/** Required here, because it is the only thing that can draw the block. */
|
|
88
|
+
preview: ComponentType<BlockPreviewProps<D>>;
|
|
89
|
+
});
|
|
72
90
|
/** A definition with its data type erased, so definitions of different shapes compose in one array. */
|
|
73
91
|
type AnyBlockDefinition = BlockDefinition<Record<string, unknown>>;
|
|
74
92
|
/**
|
|
@@ -77,8 +95,11 @@ type AnyBlockDefinition = BlockDefinition<Record<string, unknown>>;
|
|
|
77
95
|
* on `editor`, so without it an array of differently-shaped definitions will not typecheck.
|
|
78
96
|
* `initialData` is checked against the editor's data type. That relies on `NoInfer`, so
|
|
79
97
|
* TypeScript 5.4 or later is required.
|
|
98
|
+
*
|
|
99
|
+
* `D` defaults to `Record<string, unknown>`, so a definition whose components take no
|
|
100
|
+
* annotation still gets a usable `data` rather than a bare `object`.
|
|
80
101
|
*/
|
|
81
|
-
declare function defineBlock<D extends object
|
|
102
|
+
declare function defineBlock<D extends object = Record<string, unknown>>(definition: BlockDefinition<D>): AnyBlockDefinition;
|
|
82
103
|
/** The definition for a type, or undefined; the last registration of a type wins, so a host can override a core block. */
|
|
83
104
|
declare function blockByType(definitions: AnyBlockDefinition[], type: string): AnyBlockDefinition | undefined;
|
|
84
105
|
/** The definitions offered in the slash palette, in registration order, one per type, with the last registration of a type winning. */
|
|
@@ -102,6 +123,17 @@ type BlockCanvasProps = {
|
|
|
102
123
|
*/
|
|
103
124
|
blocks: QuoinBlock[];
|
|
104
125
|
onChange: (blocks: QuoinBlock[]) => void;
|
|
126
|
+
/**
|
|
127
|
+
* Called when a block is removed through its actions menu, with the block and the index it held.
|
|
128
|
+
* It runs just after the `onChange` that reports the document without it, so a host acting on the
|
|
129
|
+
* deletion is already looking at the new array. Restore the block by supplying a `blocks` array
|
|
130
|
+
* with it spliced back at that index, the same way any other document arrives.
|
|
131
|
+
*
|
|
132
|
+
* Restore it on a later tick or a later interaction, such as the click of an Undo toast. A
|
|
133
|
+
* restore applied synchronously inside this callback batches with the echo of the deletion, so
|
|
134
|
+
* what arrives is structurally equal to the document last supplied and is ignored.
|
|
135
|
+
*/
|
|
136
|
+
onDelete?: (block: QuoinBlock, index: number) => void;
|
|
105
137
|
/** Defaults to the five core block types. Pass `[...coreBlocks, yours]` to extend them. */
|
|
106
138
|
blockTypes?: AnyBlockDefinition[];
|
|
107
139
|
upload?: UploadFn;
|
|
@@ -116,11 +148,87 @@ type BlockCanvasProps = {
|
|
|
116
148
|
'aria-label'?: string;
|
|
117
149
|
};
|
|
118
150
|
/** The editor: renders `blocks`, reports every edit through `onChange`, and accepts a new `blocks` array from outside at any time. */
|
|
119
|
-
declare function BlockCanvas({ blocks, onChange, blockTypes, upload, resolveAssetUrl, onError, readOnly, className, id, 'aria-label': ariaLabel, }: BlockCanvasProps): React.JSX.Element;
|
|
151
|
+
declare function BlockCanvas({ blocks, onChange, onDelete, blockTypes, upload, resolveAssetUrl, onError, readOnly, className, id, 'aria-label': ariaLabel, }: BlockCanvasProps): React.JSX.Element;
|
|
120
152
|
|
|
121
153
|
/** The block types Quoin ships with. Spread them alongside your own definitions. */
|
|
122
154
|
declare const coreBlocks: AnyBlockDefinition[];
|
|
123
155
|
|
|
156
|
+
/**
|
|
157
|
+
* The `data` shape each core block keeps its content under. A host that persists blocks
|
|
158
|
+
* itself reads and writes these, so they are part of the public surface rather than an
|
|
159
|
+
* implementation detail. `core-data.test.tsx` holds every one of them against the editor
|
|
160
|
+
* that writes it and the seed it starts from.
|
|
161
|
+
*
|
|
162
|
+
* Every field is declared because something writes it. The optional ones are written
|
|
163
|
+
* later than the block's first save: an image's `caption` when the author types one, its
|
|
164
|
+
* `width` and `height` once the uploaded bytes have been measured, a file's `size` when
|
|
165
|
+
* the upload reports it.
|
|
166
|
+
*/
|
|
167
|
+
/** `MARKDOWN`. The source text, not rendered HTML: Quoin stores and edits markdown. */
|
|
168
|
+
type MarkdownBlockData = {
|
|
169
|
+
markdown: string;
|
|
170
|
+
};
|
|
171
|
+
/** `CALLOUT`. The prose is under `body`, not `text`. */
|
|
172
|
+
type CalloutBlockData = {
|
|
173
|
+
tone: string;
|
|
174
|
+
body: string;
|
|
175
|
+
};
|
|
176
|
+
/** `CODE`. `language` is a free string, written through as the author typed it. */
|
|
177
|
+
type CodeBlockData = {
|
|
178
|
+
language: string;
|
|
179
|
+
code: string;
|
|
180
|
+
};
|
|
181
|
+
/** `IMAGE`. `storageKey` names the uploaded file; the host's `resolveAssetUrl` turns it into a URL. */
|
|
182
|
+
type ImageBlockData = {
|
|
183
|
+
storageKey: string;
|
|
184
|
+
alt: string;
|
|
185
|
+
caption?: string;
|
|
186
|
+
width?: number;
|
|
187
|
+
height?: number;
|
|
188
|
+
};
|
|
189
|
+
/** `FILE`. `storageKey` names the uploaded file; `filename` is what the author picked. */
|
|
190
|
+
type FileBlockData = {
|
|
191
|
+
storageKey: string;
|
|
192
|
+
filename: string;
|
|
193
|
+
size?: number;
|
|
194
|
+
};
|
|
195
|
+
/** Maps each core block's `type` string to its data shape. */
|
|
196
|
+
type CoreBlockData = {
|
|
197
|
+
MARKDOWN: MarkdownBlockData;
|
|
198
|
+
CALLOUT: CalloutBlockData;
|
|
199
|
+
CODE: CodeBlockData;
|
|
200
|
+
IMAGE: ImageBlockData;
|
|
201
|
+
FILE: FileBlockData;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
/** Props for `UploadField`; the upload function itself comes from the canvas, not from here. */
|
|
205
|
+
type UploadFieldProps = {
|
|
206
|
+
/** Names what the file is for, and is passed to the host's `upload` as its second argument. */
|
|
207
|
+
category: string;
|
|
208
|
+
/** Labels the control for both the pointer and assistive technology. */
|
|
209
|
+
label: string;
|
|
210
|
+
/** An `accept` attribute for the file input, such as `'image/*'` or `'.pdf'`. */
|
|
211
|
+
accept?: string;
|
|
212
|
+
/** Called once the upload resolves. Throwing from it is reported through the canvas `onError`. */
|
|
213
|
+
onUploaded: (result: UploadResult) => void;
|
|
214
|
+
};
|
|
215
|
+
/** A file picker wired to the canvas `upload` function, with its own busy state and inline error. */
|
|
216
|
+
declare function UploadField({ category, label, accept, onUploaded }: UploadFieldProps): React.JSX.Element;
|
|
217
|
+
|
|
218
|
+
/** Props for `FilePickerButton`. */
|
|
219
|
+
type FilePickerButtonProps = {
|
|
220
|
+
/** Labels the button and the file input behind it. */
|
|
221
|
+
label: string;
|
|
222
|
+
/** An `accept` attribute for the file input, such as `'image/*'` or `'.pdf'`. */
|
|
223
|
+
accept?: string;
|
|
224
|
+
/** Greys the button out and disables the input behind it. */
|
|
225
|
+
disabled?: boolean;
|
|
226
|
+
/** Called with the chosen file, and again if the same file is picked after a failure. */
|
|
227
|
+
onPick: (file: File) => void;
|
|
228
|
+
};
|
|
229
|
+
/** A button that opens the file picker and hands back the chosen file, performing no upload of its own. */
|
|
230
|
+
declare function FilePickerButton({ label, accept, disabled, onPick }: FilePickerButtonProps): React.JSX.Element;
|
|
231
|
+
|
|
124
232
|
/** The resolved canvas configuration every block editor reads through `useQuoin`. */
|
|
125
233
|
type QuoinConfig = {
|
|
126
234
|
blockTypes: AnyBlockDefinition[];
|
|
@@ -160,15 +268,16 @@ declare function useBlockList(initial: QuoinBlock[]): BlockList;
|
|
|
160
268
|
|
|
161
269
|
/** Where a debounced save stands, for a "Saving..." or "Saved" indicator. */
|
|
162
270
|
type AutosaveStatus = 'idle' | 'saving' | 'saved' | 'retrying';
|
|
163
|
-
type SaveResult = {
|
|
164
|
-
ok?: boolean;
|
|
165
|
-
} | void;
|
|
166
271
|
/** What `useAutosave` tracks, how to build the payload, and how to persist it. */
|
|
167
272
|
type UseAutosaveInput<T> = {
|
|
168
273
|
/** The tracked fields. An edit to any of them marks dirty and restarts the debounce. */
|
|
169
274
|
deps: React.DependencyList;
|
|
170
275
|
build: () => T;
|
|
171
|
-
|
|
276
|
+
/**
|
|
277
|
+
* Persists the payload. Return anything: a mutation or a `fetch` that resolves to a body
|
|
278
|
+
* can be passed straight in. A save fails by rejecting, or by resolving to `{ ok: false }`.
|
|
279
|
+
*/
|
|
280
|
+
save: (payload: T) => unknown;
|
|
172
281
|
debounceMs?: number;
|
|
173
282
|
maxBackoffMs?: number;
|
|
174
283
|
};
|
|
@@ -279,4 +388,4 @@ declare function useMarkdownKeymap({ commit, onOpenPalette, }: {
|
|
|
279
388
|
onPaste: (event: React.ClipboardEvent<HTMLTextAreaElement>) => void;
|
|
280
389
|
};
|
|
281
390
|
|
|
282
|
-
export { type AnyBlockDefinition, type AutosaveStatus, BlockCanvas, type BlockCanvasProps, type BlockDefinition, type BlockEditorProps, type BlockList, type BlockPreviewProps, type CaretRect, type Edit, type InsertableCommand, type LinePrefix, type QuoinBlock, type QuoinConfig, type QuoinConfigInput, QuoinProvider, TEXT_COMMANDS, type TextCommand, type UndoToken, type UploadFn, type UploadResult, type UseAutosaveInput, type UseAutosaveResult, type WrapKind, applyEdit, blockByType, caretRect, continueList, coreBlocks, defineBlock, formatShortcut, indentList, insertCommand, lineAt, linkPaste, paletteBlocks, shouldOpenPalette, toggleLinePrefix, useAutoGrow, useAutosave, useBlockList, useMarkdownKeymap, useQuoin, wrapSelection };
|
|
391
|
+
export { type AnyBlockDefinition, type AutosaveStatus, BlockCanvas, type BlockCanvasProps, type BlockDefinition, type BlockEditorProps, type BlockList, type BlockPreviewProps, type CalloutBlockData, type CaretRect, type CodeBlockData, type CoreBlockData, type Edit, type FileBlockData, FilePickerButton, type FilePickerButtonProps, type ImageBlockData, type InsertableCommand, type LinePrefix, type MarkdownBlockData, type QuoinBlock, type QuoinConfig, type QuoinConfigInput, QuoinProvider, TEXT_COMMANDS, type TextCommand, type UndoToken, UploadField, type UploadFieldProps, type UploadFn, type UploadResult, type UseAutosaveInput, type UseAutosaveResult, type WrapKind, applyEdit, blockByType, caretRect, continueList, coreBlocks, defineBlock, formatShortcut, indentList, insertCommand, lineAt, linkPaste, paletteBlocks, shouldOpenPalette, toggleLinePrefix, useAutoGrow, useAutosave, useBlockList, useMarkdownKeymap, useQuoin, wrapSelection };
|