@dxos/react-ui-editor 0.10.0 → 0.11.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.
- package/dist/lib/index.mjs +1477 -0
- package/dist/lib/index.mjs.map +1 -0
- package/dist/lib/translations.mjs +32 -0
- package/dist/lib/translations.mjs.map +1 -0
- package/dist/types/src/components/Editor/Editor.d.ts +22 -17
- package/dist/types/src/components/Editor/Editor.d.ts.map +1 -1
- package/dist/types/src/components/Editor/EditorContext.d.ts +20 -0
- package/dist/types/src/components/Editor/EditorContext.d.ts.map +1 -0
- package/dist/types/src/components/Editor/EditorView.d.ts +1 -2
- package/dist/types/src/components/Editor/EditorView.d.ts.map +1 -1
- package/dist/types/src/components/Editor/index.d.ts +2 -0
- package/dist/types/src/components/Editor/index.d.ts.map +1 -1
- package/dist/types/src/components/EditorMenuProvider/EditorMenuProvider.d.ts +7 -1
- package/dist/types/src/components/EditorMenuProvider/EditorMenuProvider.d.ts.map +1 -1
- package/dist/types/src/components/EditorMenuProvider/menu.d.ts +4 -2
- package/dist/types/src/components/EditorMenuProvider/menu.d.ts.map +1 -1
- package/dist/types/src/components/EditorMenuProvider/useEditorMenu.d.ts +7 -2
- package/dist/types/src/components/EditorMenuProvider/useEditorMenu.d.ts.map +1 -1
- package/dist/types/src/components/EditorPreviewProvider/EditorPreviewContext.d.ts +18 -0
- package/dist/types/src/components/EditorPreviewProvider/EditorPreviewContext.d.ts.map +1 -0
- package/dist/types/src/components/EditorPreviewProvider/EditorPreviewProvider.d.ts +0 -6
- package/dist/types/src/components/EditorPreviewProvider/EditorPreviewProvider.d.ts.map +1 -1
- package/dist/types/src/components/EditorPreviewProvider/index.d.ts +1 -0
- package/dist/types/src/components/EditorPreviewProvider/index.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts +4 -1
- package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/index.d.ts +1 -0
- package/dist/types/src/components/EditorToolbar/index.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/lists.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/view-mode.d.ts +27 -2
- package/dist/types/src/components/EditorToolbar/view-mode.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +1 -0
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +0 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/stories/Assistant.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Automerge.stories.d.ts +16 -39
- package/dist/types/src/stories/Automerge.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Blocks.stories.d.ts +10 -0
- package/dist/types/src/stories/Blocks.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Comments.stories.d.ts +53 -14
- package/dist/types/src/stories/Comments.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Diff.stories.d.ts +32 -0
- package/dist/types/src/stories/Diff.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Experimental.stories.d.ts +1 -0
- package/dist/types/src/stories/Experimental.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Folding.stories.d.ts +18 -0
- package/dist/types/src/stories/Folding.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Outliner.stories.d.ts +4 -4
- package/dist/types/src/stories/Outliner.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Popover.stories.d.ts +3 -3
- package/dist/types/src/stories/Popover.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Suggest.stories.d.ts +27 -0
- package/dist/types/src/stories/Suggest.stories.d.ts.map +1 -0
- package/dist/types/src/stories/TrackChanges.stories.d.ts +44 -0
- package/dist/types/src/stories/TrackChanges.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Widgets.stories.d.ts +12 -0
- package/dist/types/src/stories/Widgets.stories.d.ts.map +1 -1
- package/dist/types/src/stories/components/EditorStory.d.ts.map +1 -1
- package/dist/types/src/stories/components/util.d.ts +16 -0
- package/dist/types/src/stories/components/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +40 -83
- package/src/components/Editor/Editor.tsx +142 -35
- package/src/components/Editor/EditorContext.ts +34 -0
- package/src/components/Editor/EditorView.tsx +9 -6
- package/src/components/Editor/index.ts +3 -0
- package/src/components/EditorMenuProvider/EditorMenuProvider.tsx +98 -8
- package/src/components/EditorMenuProvider/menu.ts +4 -2
- package/src/components/EditorMenuProvider/useEditorMenu.ts +114 -29
- package/src/components/EditorPreviewProvider/EditorPreviewContext.ts +21 -0
- package/src/components/EditorPreviewProvider/EditorPreviewProvider.tsx +1 -10
- package/src/components/EditorPreviewProvider/index.ts +2 -0
- package/src/components/EditorToolbar/EditorToolbar.tsx +6 -3
- package/src/components/EditorToolbar/index.ts +1 -0
- package/src/components/EditorToolbar/lists.ts +2 -6
- package/src/components/EditorToolbar/view-mode.ts +41 -12
- package/src/components/index.ts +1 -0
- package/src/index.ts +0 -1
- package/src/{extensions → stories}/Assistant.stories.tsx +7 -2
- package/src/stories/Automerge.stories.tsx +99 -78
- package/src/stories/Blocks.stories.tsx +83 -0
- package/src/stories/Comments.stories.tsx +273 -74
- package/src/stories/Diff.stories.tsx +48 -0
- package/src/stories/EditorToolbar.stories.tsx +2 -2
- package/src/stories/Experimental.stories.tsx +13 -2
- package/src/stories/Folding.stories.tsx +120 -0
- package/src/stories/Markdown.stories.tsx +1 -1
- package/src/stories/Outliner.stories.tsx +18 -7
- package/src/stories/Popover.stories.tsx +27 -5
- package/src/stories/Suggest.stories.tsx +199 -0
- package/src/stories/TrackChanges.stories.tsx +226 -0
- package/src/stories/Widgets.stories.tsx +162 -10
- package/src/stories/components/EditorStory.tsx +15 -6
- package/src/stories/components/util.tsx +40 -2
- package/dist/lib/browser/index.mjs +0 -1676
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/translations.mjs +0 -39
- package/dist/lib/browser/translations.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -1678
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/translations.mjs +0 -41
- package/dist/lib/node-esm/translations.mjs.map +0 -7
- package/dist/types/src/extensions/Assistant.stories.d.ts.map +0 -1
- package/dist/types/src/extensions/assistant-extension.d.ts +0 -24
- package/dist/types/src/extensions/assistant-extension.d.ts.map +0 -1
- package/dist/types/src/extensions/index.d.ts +0 -2
- package/dist/types/src/extensions/index.d.ts.map +0 -1
- package/src/extensions/assistant-extension.tsx +0 -223
- package/src/extensions/index.ts +0 -5
- /package/dist/types/src/{extensions → stories}/Assistant.stories.d.ts +0 -0
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
13
|
-
import React, { useEffect, useMemo, useState } from 'react';
|
|
13
|
+
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
|
14
14
|
import { createPortal } from 'react-dom';
|
|
15
15
|
|
|
16
16
|
import { random } from '@dxos/random';
|
|
@@ -35,9 +35,11 @@ import { EditorPreviewProvider, useEditorPreview } from '../components';
|
|
|
35
35
|
import { useTextEditor } from '../hooks';
|
|
36
36
|
import { EditorStory } from './components';
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
random.seed(123);
|
|
39
|
+
|
|
40
|
+
//
|
|
39
41
|
// XmlTags helpers
|
|
40
|
-
//
|
|
42
|
+
//
|
|
41
43
|
|
|
42
44
|
const xmlRegistry = {
|
|
43
45
|
test: {
|
|
@@ -85,9 +87,9 @@ const XmlTagsStory = ({ text }: { text?: string }) => {
|
|
|
85
87
|
);
|
|
86
88
|
};
|
|
87
89
|
|
|
88
|
-
//
|
|
90
|
+
//
|
|
89
91
|
// Preview helpers
|
|
90
|
-
//
|
|
92
|
+
//
|
|
91
93
|
|
|
92
94
|
const handlePreviewLookup = async ({ dxn, label }: PreviewLinkRef): Promise<PreviewLinkTarget> => {
|
|
93
95
|
random.seed(dxn.split('').reduce((acc: number, char: string) => acc + char.charCodeAt(0), 1));
|
|
@@ -140,16 +142,82 @@ const PreviewBlockCard = ({ dxn, label }: XmlWidgetProps<{ dxn: string; label: s
|
|
|
140
142
|
</Card.Header>
|
|
141
143
|
{text && (
|
|
142
144
|
<Card.Row>
|
|
143
|
-
<Card.Text
|
|
145
|
+
<Card.Text classNames='text-description'>{text}</Card.Text>
|
|
144
146
|
</Card.Row>
|
|
145
147
|
)}
|
|
146
148
|
</Card.Root>
|
|
147
149
|
);
|
|
148
150
|
};
|
|
149
151
|
|
|
150
|
-
|
|
152
|
+
/** Obsidian-style height suffix in the image label: ``. */
|
|
153
|
+
const parseBlockHeight = (label = ''): number | undefined => {
|
|
154
|
+
const match = /\|(\d+)$/.exec(label);
|
|
155
|
+
return match ? Number.parseInt(match[1], 10) : undefined;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Fixed-height block that mirrors the plugin-markdown sketch embed: it renders at exactly the height
|
|
160
|
+
* encoded in the label, so CM's reserved `estimatedHeight` and the measured height match — the setup
|
|
161
|
+
* that exercises the scroll/cull path (jitter, blank, flash, jump) without needing ECHO.
|
|
162
|
+
*/
|
|
163
|
+
const FixedHeightPreview = ({ label, dxn }: XmlWidgetProps<{ label: string; dxn: string }>) => {
|
|
164
|
+
const height = parseBlockHeight(label) ?? 200;
|
|
165
|
+
return (
|
|
166
|
+
<div
|
|
167
|
+
style={{ height }}
|
|
168
|
+
className='grid place-items-center border border-separator rounded-md bg-base-surface text-description'
|
|
169
|
+
>
|
|
170
|
+
{label} · {height}px · {dxn}
|
|
171
|
+
</div>
|
|
172
|
+
);
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Faithfully mimics a Surface-backed embed (the real plugin-markdown block): the content mounts
|
|
177
|
+
* asynchronously (like a Surface resolving) and runs an inner ResizeObserver (like the sketch's
|
|
178
|
+
* auto-fit) that re-lays-out whenever the container size changes — including the 0↔height blips that
|
|
179
|
+
* CM's scroll-culling produces as the node is detached and re-parented.
|
|
180
|
+
*
|
|
181
|
+
* NOTE: The scroll-*jump* on large scroll deltas is NOT specific to this async variant — verified via
|
|
182
|
+
* Playwright, `FixedHeightPreview` (plain inert div) jumps identically. It is CM's height-estimate
|
|
183
|
+
* re-anchor, not the widget. See `StubWidget` and CM #1727.
|
|
184
|
+
*/
|
|
185
|
+
const SurfaceLikePreview = ({ label, dxn }: XmlWidgetProps<{ label: string; dxn: string }>) => {
|
|
186
|
+
const height = parseBlockHeight(label) ?? 200;
|
|
187
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
188
|
+
const [resolved, setResolved] = useState(false);
|
|
189
|
+
// Async resolution, like a Surface looking up + mounting its component.
|
|
190
|
+
useEffect(() => {
|
|
191
|
+
const timer = setTimeout(() => setResolved(true), 30);
|
|
192
|
+
return () => clearTimeout(timer);
|
|
193
|
+
}, []);
|
|
194
|
+
// Inner ResizeObserver that does layout work on every size change, like the sketch's auto-fit.
|
|
195
|
+
useEffect(() => {
|
|
196
|
+
const element = ref.current;
|
|
197
|
+
if (!element) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
const observer = new ResizeObserver(() => {
|
|
201
|
+
// Touch layout the way an auto-fit would (read forces reflow).
|
|
202
|
+
void element.clientHeight;
|
|
203
|
+
});
|
|
204
|
+
observer.observe(element);
|
|
205
|
+
return () => observer.disconnect();
|
|
206
|
+
}, []);
|
|
207
|
+
return (
|
|
208
|
+
<div
|
|
209
|
+
ref={ref}
|
|
210
|
+
style={{ height }}
|
|
211
|
+
className='grid place-items-center border border-separator rounded-md bg-base-surface text-description'
|
|
212
|
+
>
|
|
213
|
+
{resolved ? `Surface ${label} · ${height}px · ${dxn}` : 'resolving…'}
|
|
214
|
+
</div>
|
|
215
|
+
);
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
//
|
|
151
219
|
// Meta
|
|
152
|
-
//
|
|
220
|
+
//
|
|
153
221
|
|
|
154
222
|
const meta = {
|
|
155
223
|
title: 'ui/react-ui-editor/Widgets',
|
|
@@ -161,9 +229,9 @@ export default meta;
|
|
|
161
229
|
|
|
162
230
|
type Story = StoryObj<typeof meta>;
|
|
163
231
|
|
|
164
|
-
//
|
|
232
|
+
//
|
|
165
233
|
// Stories
|
|
166
|
-
//
|
|
234
|
+
//
|
|
167
235
|
|
|
168
236
|
const xmlTagsText = trim`
|
|
169
237
|
# XML Tags
|
|
@@ -197,6 +265,8 @@ const previewText = trim`
|
|
|
197
265
|
|
|
198
266
|

|
|
199
267
|
|
|
268
|
+
Text
|
|
269
|
+
|
|
200
270
|
`;
|
|
201
271
|
|
|
202
272
|
/**
|
|
@@ -239,3 +309,85 @@ export const Preview: Story = {
|
|
|
239
309
|
);
|
|
240
310
|
},
|
|
241
311
|
};
|
|
312
|
+
|
|
313
|
+
const filler = (marker: string) =>
|
|
314
|
+
Array.from({ length: 20 }, (_, index) => `${marker} ${index + 1} - ${random.lorem.paragraphs()}`).join('\n\n');
|
|
315
|
+
|
|
316
|
+
const previewScrollText = [
|
|
317
|
+
'# Preview blocks (scroll test)',
|
|
318
|
+
filler('Above'),
|
|
319
|
+
'',
|
|
320
|
+
filler('Below'),
|
|
321
|
+
].join('\n\n');
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* A fixed-height (400px) `echo:` block embed in a long scrollable document. Sets `estimatedHeight`
|
|
325
|
+
* from the label so CM reserves the right space, matching the plugin-markdown sketch embed. Use this
|
|
326
|
+
* to reproduce scroll behavior: scroll the block off-screen and back, and past the viewport edges.
|
|
327
|
+
*/
|
|
328
|
+
export const PreviewScroll: Story = {
|
|
329
|
+
render: () => {
|
|
330
|
+
const [widgets, setWidgets] = useState<XmlWidgetState[]>([]);
|
|
331
|
+
const extensions = useMemo(
|
|
332
|
+
() => [
|
|
333
|
+
xmlTags({
|
|
334
|
+
registry: {
|
|
335
|
+
'dxn-preview': {
|
|
336
|
+
block: true,
|
|
337
|
+
urlSchemes: ['dxn:', 'echo:'],
|
|
338
|
+
estimatedHeight: ({ label }: XmlWidgetProps<{ label?: string }>) => parseBlockHeight(label),
|
|
339
|
+
Component: FixedHeightPreview,
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
setWidgets,
|
|
343
|
+
}),
|
|
344
|
+
],
|
|
345
|
+
[],
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
return (
|
|
349
|
+
<>
|
|
350
|
+
<EditorStory text={previewScrollText} extensions={extensions} />
|
|
351
|
+
{widgets.map(({ id, root, Component, props }) => (
|
|
352
|
+
<div key={id}>{createPortal(<Component {...props} />, root)}</div>
|
|
353
|
+
))}
|
|
354
|
+
</>
|
|
355
|
+
);
|
|
356
|
+
},
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Same long scrollable document as `PreviewScroll`, but the block renders a Surface-like component
|
|
361
|
+
* (async mount + inner ResizeObserver). Use this to reproduce the scroll jump that only appears with
|
|
362
|
+
* Surface-backed embeds, and to verify fixes against it.
|
|
363
|
+
*/
|
|
364
|
+
export const PreviewScrollSurface: Story = {
|
|
365
|
+
render: () => {
|
|
366
|
+
const [widgets, setWidgets] = useState<XmlWidgetState[]>([]);
|
|
367
|
+
const extensions = useMemo(
|
|
368
|
+
() => [
|
|
369
|
+
xmlTags({
|
|
370
|
+
registry: {
|
|
371
|
+
'dxn-preview': {
|
|
372
|
+
block: true,
|
|
373
|
+
urlSchemes: ['dxn:', 'echo:'],
|
|
374
|
+
estimatedHeight: ({ label }: XmlWidgetProps<{ label?: string }>) => parseBlockHeight(label),
|
|
375
|
+
Component: SurfaceLikePreview,
|
|
376
|
+
},
|
|
377
|
+
},
|
|
378
|
+
setWidgets,
|
|
379
|
+
}),
|
|
380
|
+
],
|
|
381
|
+
[],
|
|
382
|
+
);
|
|
383
|
+
|
|
384
|
+
return (
|
|
385
|
+
<>
|
|
386
|
+
<EditorStory text={previewScrollText} extensions={extensions} />
|
|
387
|
+
{widgets.map(({ id, root, Component, props }) => (
|
|
388
|
+
<div key={id}>{createPortal(<Component {...props} />, root)}</div>
|
|
389
|
+
))}
|
|
390
|
+
</>
|
|
391
|
+
);
|
|
392
|
+
},
|
|
393
|
+
};
|
|
@@ -9,7 +9,6 @@ import { Obj } from '@dxos/echo';
|
|
|
9
9
|
import { TestSchema } from '@dxos/echo/testing';
|
|
10
10
|
import { invariant } from '@dxos/invariant';
|
|
11
11
|
import { PublicKey } from '@dxos/keys';
|
|
12
|
-
import { log } from '@dxos/log';
|
|
13
12
|
import { useMergeRefs, useThemeContext } from '@dxos/react-ui';
|
|
14
13
|
import { useAttentionAttributes } from '@dxos/react-ui-attention';
|
|
15
14
|
import { Syntax } from '@dxos/react-ui-syntax-highlighter';
|
|
@@ -50,6 +49,7 @@ export const EditorStory = forwardRef<EditorController, EditorStoryProps>(
|
|
|
50
49
|
({ debug, debugCustom, text, extensions: extensionsProp, ...props }, forwardedRef) => {
|
|
51
50
|
const controllerRef = useRef<EditorController>(null);
|
|
52
51
|
const mergedRef = useMergeRefs([controllerRef, forwardedRef]);
|
|
52
|
+
const view = controllerRef.current?.view;
|
|
53
53
|
|
|
54
54
|
const attentionAttrs = useAttentionAttributes('test-panel');
|
|
55
55
|
const [tree, setTree] = useState<DebugNode>();
|
|
@@ -60,14 +60,13 @@ export const EditorStory = forwardRef<EditorController, EditorStoryProps>(
|
|
|
60
60
|
[debug, extensionsProp],
|
|
61
61
|
);
|
|
62
62
|
|
|
63
|
-
const view = controllerRef.current?.view;
|
|
64
63
|
return (
|
|
65
64
|
<div className={mx('dx-container grid', debug && 'grid-cols-2 lg:grid-cols-[1fr_600px]')}>
|
|
66
65
|
<EditorComponent ref={mergedRef} object={object} text={text} extensions={extensions} {...props} />
|
|
67
66
|
|
|
68
67
|
{debug && (
|
|
69
68
|
<div
|
|
70
|
-
className='grid h-full auto-rows-fr border-l border-separator divide-y divide-separator overflow-hidden'
|
|
69
|
+
className='grid h-full auto-rows-fr border-l border-separator divide-y divide-subdued-separator overflow-hidden'
|
|
71
70
|
{...attentionAttrs}
|
|
72
71
|
>
|
|
73
72
|
{view && debugCustom?.(view)}
|
|
@@ -124,8 +123,19 @@ const EditorComponent = forwardRef<EditorController, EditorStoryProps>(
|
|
|
124
123
|
selection,
|
|
125
124
|
initialValue: text,
|
|
126
125
|
extensions: [
|
|
127
|
-
createBasicExtensions({
|
|
128
|
-
|
|
126
|
+
createBasicExtensions({
|
|
127
|
+
lineNumbers,
|
|
128
|
+
placeholder,
|
|
129
|
+
readOnly,
|
|
130
|
+
scrollPastEnd: true,
|
|
131
|
+
search: true,
|
|
132
|
+
}),
|
|
133
|
+
createThemeExtensions({
|
|
134
|
+
monospace,
|
|
135
|
+
slots,
|
|
136
|
+
syntaxHighlighting: true,
|
|
137
|
+
themeMode,
|
|
138
|
+
}),
|
|
129
139
|
createMarkdownExtensions(),
|
|
130
140
|
extensions || [],
|
|
131
141
|
],
|
|
@@ -135,7 +145,6 @@ const EditorComponent = forwardRef<EditorController, EditorStoryProps>(
|
|
|
135
145
|
|
|
136
146
|
// External controller.
|
|
137
147
|
useImperativeHandle(forwardedRef, () => {
|
|
138
|
-
log.info('view updated', { id });
|
|
139
148
|
return createEditorController(view);
|
|
140
149
|
}, [id, view]);
|
|
141
150
|
|
|
@@ -13,18 +13,56 @@ import {
|
|
|
13
13
|
folding,
|
|
14
14
|
formattingKeymap,
|
|
15
15
|
image,
|
|
16
|
+
join,
|
|
16
17
|
linkTooltip,
|
|
17
18
|
table,
|
|
18
19
|
} from '@dxos/ui-editor';
|
|
19
20
|
import { type RenderCallback } from '@dxos/ui-editor/types';
|
|
20
21
|
import { safeUrl } from '@dxos/util';
|
|
21
22
|
|
|
23
|
+
random.seed(1);
|
|
24
|
+
|
|
22
25
|
import { str } from '../../util';
|
|
23
26
|
|
|
24
27
|
export const num = () => random.number.int({ min: 0, max: 9999 }).toLocaleString();
|
|
25
28
|
|
|
26
29
|
export const img = '';
|
|
27
30
|
|
|
31
|
+
export type GenerateListOptions = {
|
|
32
|
+
/** Maximum nesting depth. */
|
|
33
|
+
depth?: number;
|
|
34
|
+
/** Children per node — a fixed count or an inclusive `[min, max]` range. */
|
|
35
|
+
children?: number | [number, number];
|
|
36
|
+
/** Emit task markers (`- [ ]`) rather than plain bullets (`- `). */
|
|
37
|
+
task?: boolean;
|
|
38
|
+
/** Spaces of indentation per level. */
|
|
39
|
+
indent?: number;
|
|
40
|
+
/** Content generator for each item (default: a lorem sentence). */
|
|
41
|
+
content?: () => string;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Generates a hierarchical markdown list for the outliner stories. Deterministic under `random.seed`.
|
|
46
|
+
*/
|
|
47
|
+
export const generateList = ({
|
|
48
|
+
depth = 3,
|
|
49
|
+
children = [1, 3],
|
|
50
|
+
task = true,
|
|
51
|
+
indent = 2,
|
|
52
|
+
content = () => random.lorem.sentence(),
|
|
53
|
+
}: GenerateListOptions = {}): string => {
|
|
54
|
+
const count = (value: number | [number, number]): number =>
|
|
55
|
+
Array.isArray(value) ? random.number.int({ min: value[0], max: value[1] }) : value;
|
|
56
|
+
|
|
57
|
+
const build = (level: number): string[] =>
|
|
58
|
+
Array.from({ length: count(children) }).flatMap(() => {
|
|
59
|
+
const line = ' '.repeat(indent * level) + (task ? '- [ ] ' : '- ') + content();
|
|
60
|
+
return level + 1 < depth ? [line, ...build(level + 1)] : [line];
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
return join(...build(0));
|
|
64
|
+
};
|
|
65
|
+
|
|
28
66
|
export const code = str(
|
|
29
67
|
// prettier-ignore
|
|
30
68
|
'// Code',
|
|
@@ -231,13 +269,13 @@ export const renderLinkButton: RenderCallback<{ url: string }> = (el, { url }) =
|
|
|
231
269
|
export const defaultExtensions: Extension[] = [
|
|
232
270
|
decorateMarkdown({ renderLinkButton, selectionChangeDelay: 100 }),
|
|
233
271
|
formattingKeymap(),
|
|
234
|
-
linkTooltip(renderLinkTooltip),
|
|
272
|
+
linkTooltip({ render: renderLinkTooltip }),
|
|
235
273
|
];
|
|
236
274
|
|
|
237
275
|
export const allExtensions: Extension[] = [
|
|
238
276
|
decorateMarkdown({ renderLinkButton, selectionChangeDelay: 100, numberedHeadings: { from: 2, to: 4 } }),
|
|
239
277
|
formattingKeymap(),
|
|
240
|
-
linkTooltip(renderLinkTooltip),
|
|
278
|
+
linkTooltip({ render: renderLinkTooltip }),
|
|
241
279
|
image(),
|
|
242
280
|
table(),
|
|
243
281
|
folding(),
|