@dxos/react-ui-markdown 0.8.4-main.fcc0d83b33 → 0.8.4-staging.60fe92afc8

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 (27) hide show
  1. package/LICENSE +102 -5
  2. package/dist/lib/browser/index.mjs +41 -18
  3. package/dist/lib/browser/index.mjs.map +4 -4
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/types/src/MarkdownStream/MarkdownStream.d.ts.map +1 -1
  6. package/dist/types/src/MarkdownStream/stream.d.ts.map +1 -1
  7. package/dist/types/src/{MarkdownBlock/MarkdownBlock.d.ts → MarkdownView/MarkdownView.d.ts} +3 -3
  8. package/dist/types/src/MarkdownView/MarkdownView.d.ts.map +1 -0
  9. package/dist/types/src/{MarkdownBlock/MarkdownBlock.stories.d.ts → MarkdownView/MarkdownView.stories.d.ts} +4 -4
  10. package/dist/types/src/MarkdownView/MarkdownView.stories.d.ts.map +1 -0
  11. package/dist/types/src/MarkdownView/index.d.ts +2 -0
  12. package/dist/types/src/MarkdownView/index.d.ts.map +1 -0
  13. package/dist/types/src/index.d.ts +1 -1
  14. package/dist/types/src/index.d.ts.map +1 -1
  15. package/dist/types/tsconfig.tsbuildinfo +1 -1
  16. package/package.json +36 -36
  17. package/src/MarkdownStream/MarkdownStream.stories.tsx +1 -1
  18. package/src/MarkdownStream/MarkdownStream.tsx +17 -16
  19. package/src/MarkdownStream/stream.ts +1 -1
  20. package/src/{MarkdownBlock/MarkdownBlock.stories.tsx → MarkdownView/MarkdownView.stories.tsx} +6 -6
  21. package/src/{MarkdownBlock/MarkdownBlock.tsx → MarkdownView/MarkdownView.tsx} +19 -3
  22. package/src/{MarkdownBlock → MarkdownView}/index.ts +1 -1
  23. package/src/index.ts +1 -1
  24. package/dist/types/src/MarkdownBlock/MarkdownBlock.d.ts.map +0 -1
  25. package/dist/types/src/MarkdownBlock/MarkdownBlock.stories.d.ts.map +0 -1
  26. package/dist/types/src/MarkdownBlock/index.d.ts +0 -2
  27. package/dist/types/src/MarkdownBlock/index.d.ts.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-markdown",
3
- "version": "0.8.4-main.fcc0d83b33",
3
+ "version": "0.8.4-staging.60fe92afc8",
4
4
  "description": "Markdown components.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -8,14 +8,14 @@
8
8
  "type": "git",
9
9
  "url": "https://github.com/dxos/dxos"
10
10
  },
11
- "license": "MIT",
11
+ "license": "FSL-1.1-Apache-2.0",
12
12
  "author": "DXOS.org",
13
13
  "type": "module",
14
14
  "exports": {
15
15
  ".": {
16
16
  "source": "./src/index.ts",
17
17
  "types": "./dist/types/src/index.d.ts",
18
- "browser": "./dist/lib/browser/index.mjs"
18
+ "default": "./dist/lib/browser/index.mjs"
19
19
  }
20
20
  },
21
21
  "types": "dist/types/src/index.d.ts",
@@ -24,33 +24,33 @@
24
24
  "src"
25
25
  ],
26
26
  "dependencies": {
27
- "@codemirror/autocomplete": "^6.19.0",
28
- "@codemirror/language": "^6.11.3",
29
- "@codemirror/state": "^6.5.2",
30
- "@codemirror/view": "^6.38.4",
31
- "@lezer/common": "^1.2.2",
32
- "@lezer/highlight": "^1.2.1",
33
- "@lezer/markdown": "^1.3.1",
27
+ "@codemirror/autocomplete": "^6.20.2",
28
+ "@codemirror/language": "^6.12.3",
29
+ "@codemirror/state": "^6.6.0",
30
+ "@codemirror/view": "^6.43.0",
31
+ "@lezer/common": "^1.5.2",
32
+ "@lezer/highlight": "^1.2.3",
33
+ "@lezer/markdown": "^1.6.3",
34
34
  "@lezer/xml": "^1.0.6",
35
35
  "@radix-ui/react-compose-refs": "1.1.1",
36
36
  "@radix-ui/react-context": "1.1.1",
37
- "effect": "3.20.0",
37
+ "effect": "3.21.3",
38
38
  "json5": "^2.2.3",
39
39
  "react-markdown": "^10.1.0",
40
40
  "react-resize-detector": "^11.0.1",
41
41
  "remark-gfm": "^4.0.1",
42
- "@dxos/async": "0.8.4-main.fcc0d83b33",
43
- "@dxos/echo": "0.8.4-main.fcc0d83b33",
44
- "@dxos/effect": "0.8.4-main.fcc0d83b33",
45
- "@dxos/invariant": "0.8.4-main.fcc0d83b33",
46
- "@dxos/log": "0.8.4-main.fcc0d83b33",
47
- "@dxos/react-ui": "0.8.4-main.fcc0d83b33",
48
- "@dxos/react-ui-syntax-highlighter": "0.8.4-main.fcc0d83b33",
49
- "@dxos/react-ui-editor": "0.8.4-main.fcc0d83b33",
50
- "@dxos/ui-editor": "0.8.4-main.fcc0d83b33",
51
- "@dxos/ui": "0.8.4-main.fcc0d83b33",
52
- "@dxos/util": "0.8.4-main.fcc0d83b33",
53
- "@dxos/ui-theme": "0.8.4-main.fcc0d83b33"
42
+ "@dxos/async": "0.8.4-staging.60fe92afc8",
43
+ "@dxos/effect": "0.8.4-staging.60fe92afc8",
44
+ "@dxos/invariant": "0.8.4-staging.60fe92afc8",
45
+ "@dxos/log": "0.8.4-staging.60fe92afc8",
46
+ "@dxos/echo": "0.8.4-staging.60fe92afc8",
47
+ "@dxos/react-ui-editor": "0.8.4-staging.60fe92afc8",
48
+ "@dxos/react-ui-syntax-highlighter": "0.8.4-staging.60fe92afc8",
49
+ "@dxos/ui-theme": "0.8.4-staging.60fe92afc8",
50
+ "@dxos/ui-editor": "0.8.4-staging.60fe92afc8",
51
+ "@dxos/ui": "0.8.4-staging.60fe92afc8",
52
+ "@dxos/util": "0.8.4-staging.60fe92afc8",
53
+ "@dxos/react-ui": "0.8.4-staging.60fe92afc8"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@effect/vitest": "0.29.0",
@@ -58,23 +58,23 @@
58
58
  "@types/react-dom": "~19.2.3",
59
59
  "react": "~19.2.3",
60
60
  "react-dom": "~19.2.3",
61
- "vite": "^8.0.10",
62
- "@dxos/echo": "0.8.4-main.fcc0d83b33",
63
- "@dxos/lit-ui": "0.8.4-main.fcc0d83b33",
64
- "@dxos/keys": "0.8.4-main.fcc0d83b33",
65
- "@dxos/random": "0.8.4-main.fcc0d83b33",
66
- "@dxos/react-client": "0.8.4-main.fcc0d83b33",
67
- "@dxos/react-ui": "0.8.4-main.fcc0d83b33",
68
- "@dxos/schema": "0.8.4-main.fcc0d83b33",
69
- "@dxos/storybook-utils": "0.8.4-main.fcc0d83b33",
70
- "@dxos/ui-theme": "0.8.4-main.fcc0d83b33"
61
+ "vite": "^8.0.16",
62
+ "@dxos/echo": "0.8.4-staging.60fe92afc8",
63
+ "@dxos/keys": "0.8.4-staging.60fe92afc8",
64
+ "@dxos/random": "0.8.4-staging.60fe92afc8",
65
+ "@dxos/lit-ui": "0.8.4-staging.60fe92afc8",
66
+ "@dxos/react-client": "0.8.4-staging.60fe92afc8",
67
+ "@dxos/schema": "0.8.4-staging.60fe92afc8",
68
+ "@dxos/react-ui": "0.8.4-staging.60fe92afc8",
69
+ "@dxos/storybook-utils": "0.8.4-staging.60fe92afc8",
70
+ "@dxos/ui-theme": "0.8.4-staging.60fe92afc8"
71
71
  },
72
72
  "peerDependencies": {
73
- "effect": "3.20.0",
73
+ "effect": "3.21.3",
74
74
  "react": "~19.2.3",
75
75
  "react-dom": "~19.2.3",
76
- "@dxos/react-ui": "0.8.4-main.fcc0d83b33",
77
- "@dxos/ui-theme": "0.8.4-main.fcc0d83b33"
76
+ "@dxos/react-ui": "0.8.4-staging.60fe92afc8",
77
+ "@dxos/ui-theme": "0.8.4-staging.60fe92afc8"
78
78
  },
79
79
  "publishConfig": {
80
80
  "access": "public"
@@ -124,7 +124,7 @@ const DefaultStory = ({
124
124
  random.lorem.paragraph(),
125
125
  `<react-widget>${random.lorem.paragraphs(3)}</react-widget>`,
126
126
  '',
127
- ].join('\n\n'),
127
+ ].join('\n'),
128
128
  );
129
129
  }, [controller]);
130
130
 
@@ -21,7 +21,7 @@ import React, {
21
21
  import { createPortal } from 'react-dom';
22
22
 
23
23
  import { addEventListener } from '@dxos/async';
24
- import { runAndForwardErrors } from '@dxos/effect';
24
+ import { EffectEx } from '@dxos/effect';
25
25
  import { ErrorBoundary, type ThemedClassName, useDynamicRef, useStateWithRef, useThemeContext } from '@dxos/react-ui';
26
26
  import { useTextEditor, type UseTextEditor } from '@dxos/react-ui-editor';
27
27
  import {
@@ -37,7 +37,7 @@ import {
37
37
  navigatePreviousEffect,
38
38
  preview,
39
39
  scroller,
40
- scrollerLineEffect,
40
+ crawlerLineEffect,
41
41
  fader,
42
42
  typewriter,
43
43
  typewriterBypass,
@@ -45,10 +45,10 @@ import {
45
45
  xmlTagResetEffect,
46
46
  xmlTagUpdateEffect,
47
47
  xmlTags,
48
- autoScroll,
49
48
  documentSlots,
50
49
  xmlFormatting,
51
50
  xmlBlockDecoration,
51
+ lineSpacing,
52
52
  } from '@dxos/ui-editor';
53
53
  import { mx } from '@dxos/ui-theme';
54
54
  import { isTruthy } from '@dxos/util';
@@ -213,14 +213,12 @@ export const MarkdownStream = forwardRef<MarkdownStreamController | null, Markdo
213
213
  return (
214
214
  <>
215
215
  {/* Markdown editor. */}
216
- <div role='none' className={mx('dx-container', classNames)} ref={parentRef} />
216
+ <div className={mx('dx-container', classNames)} ref={parentRef} />
217
217
 
218
218
  {/* React widgets are rendered in portals outside of the editor. */}
219
219
  <ErrorBoundary name='markdown-stream'>
220
220
  {widgets.map(({ Component, root, id, props }) => (
221
- <div key={id} role='none'>
222
- {createPortal(<Component view={view} {...props} />, root)}
223
- </div>
221
+ <div key={id}>{createPortal(<Component view={view} {...props} />, root)}</div>
224
222
  ))}
225
223
  {footerRoot && footerVisible && createPortal(footer, footerRoot)}
226
224
  </ErrorBoundary>
@@ -272,12 +270,16 @@ const useMarkdownStreamTextEditor = (
272
270
  [
273
271
  extendedMarkdown({ registry }),
274
272
  decorateMarkdown({
275
- // `dxn:` links/images are reference widgets owned by `preview()` (PreviewInlineWidget /
273
+ // `echo:`/`dxn:` links/images are reference widgets owned by `preview()` (PreviewInlineWidget /
276
274
  // PreviewBlockWidget). Skipping them here avoids `decorateMarkdown` adding a
277
275
  // non-functional `LinkButton` anchor on top of the same node — e.g. for
278
- // `[DXOS](dxn:echo:BNPMIBEDJLRIILYUYZVM6GT64VWI6WPPZ:01KQ889PZBRNHAEECV0ANFAYX7)`.
279
- skip: (node) => (node.name === 'Link' || node.name === 'Image') && node.url.startsWith('dxn:'),
276
+ // `[DXOS](echo://BNPMIBEDJLRIILYUYZVM6GT64VWI6WPPZ/01KQ889PZBRNHAEECV0ANFAYX7)`.
277
+ skip: (node) =>
278
+ (node.name === 'Link' || node.name === 'Image') &&
279
+ (node.url.startsWith('dxn:') || node.url.startsWith('echo:')),
280
280
  }),
281
+ // TODO(burdon): Make optional; Removes need for '\n\n'.
282
+ lineSpacing(),
281
283
  preview(),
282
284
  // NOTE: An ancestor element must set `data-hue` so `.dx-panel` resolves to the user's
283
285
  // hue tokens (see `packages/ui/ui-theme/src/css/components/panel.css`). Tailwind picks
@@ -285,12 +287,11 @@ const useMarkdownStreamTextEditor = (
285
287
  xmlBlockDecoration({
286
288
  tag: 'prompt',
287
289
  lineClass: 'cm-prompt-line my-8',
288
- contentClass: 'cm-prompt-bubble dx-panel px-2 py-1.5 rounded-sm [&_*]:text-inherit!',
290
+ contentClass: 'cm-prompt-bubble dx-panel px-2 py-1.5 box-decoration-clone rounded-sm [&_*]:text-inherit!',
289
291
  hideTags: true,
290
292
  }),
291
293
  xmlTags({ registry, setWidgets, bookmarks: ['prompt'] }),
292
- scroller({ overScroll: 80 }),
293
- options?.autoScroll && autoScroll(),
294
+ scroller({ overScroll: 80, autoScroll: options?.autoScroll }),
294
295
  options?.typewriter &&
295
296
  typewriter({
296
297
  cursor: options?.cursor,
@@ -358,7 +359,7 @@ const useMarkdownStreamQueue = (
358
359
  );
359
360
 
360
361
  return () => {
361
- void runAndForwardErrors(Fiber.interrupt(fork));
362
+ void EffectEx.runAndForwardErrors(Fiber.interrupt(fork));
362
363
  };
363
364
  }, [view, queue, chunkSize, delayMs]);
364
365
  };
@@ -392,7 +393,7 @@ const createMarkdownStreamController = ({
392
393
  /** Scroll to bottom. */
393
394
  scrollToBottom: (behavior?: ScrollBehavior) => {
394
395
  viewRef.current?.dispatch({
395
- effects: scrollerLineEffect.of({ line: -1, behavior }),
396
+ effects: crawlerLineEffect.of({ line: -1, behavior }),
396
397
  });
397
398
  },
398
399
 
@@ -431,7 +432,7 @@ const createMarkdownStreamController = ({
431
432
  // collected several streaming partials before React rendered.
432
433
  const queue = queueRef.current;
433
434
  if (queue) {
434
- await runAndForwardErrors(Queue.offer(queue, text));
435
+ await EffectEx.runAndForwardErrors(Queue.offer(queue, text));
435
436
  }
436
437
  }
437
438
  },
@@ -8,7 +8,7 @@ import * as Stream from 'effect/Stream';
8
8
  import { Obj } from '@dxos/echo';
9
9
 
10
10
  export const renderObjectLink = (obj: Obj.Unknown, block?: boolean) =>
11
- `${block ? '!' : ''}[${Obj.getLabel(obj)}](${Obj.getDXN(obj).toString()})`;
11
+ `${block ? '!' : ''}[${Obj.getLabel(obj)}](${Obj.getURI(obj)})`;
12
12
 
13
13
  export type StreamerOptions = {
14
14
  /**
@@ -8,24 +8,24 @@ import { random } from '@dxos/random';
8
8
  import { withLayout, withTheme } from '@dxos/react-ui/testing';
9
9
  import { trim } from '@dxos/util';
10
10
 
11
- import { MarkdownBlock } from './MarkdownBlock';
11
+ import { MarkdownView } from './MarkdownView';
12
12
 
13
13
  random.seed(0);
14
14
 
15
15
  const meta = {
16
- title: 'ui/react-ui-markdown/MarkdownBlock',
17
- component: MarkdownBlock,
16
+ title: 'ui/react-ui-markdown/MarkdownView',
17
+ component: MarkdownView,
18
18
  decorators: [withTheme(), withLayout({ layout: 'column' })],
19
- } satisfies Meta<typeof MarkdownBlock>;
19
+ } satisfies Meta<typeof MarkdownView>;
20
20
 
21
21
  export default meta;
22
22
 
23
- type Story = StoryObj<typeof MarkdownBlock>;
23
+ type Story = StoryObj<typeof MarkdownView>;
24
24
 
25
25
  const content = trim`
26
26
  # Hello World!
27
27
 
28
- > An example of the MarkdownBlock component.
28
+ > An example of the MarkdownView component.
29
29
 
30
30
  ${random.lorem.paragraphs(1)}
31
31
 
@@ -6,11 +6,11 @@ import React, { type PropsWithChildren } from 'react';
6
6
  import ReactMarkdown, { type Options as ReactMarkdownOptions } from 'react-markdown';
7
7
  import remarkGfm from 'remark-gfm';
8
8
 
9
- import { type ThemedClassName } from '@dxos/react-ui';
9
+ import { MediaPlayer, type ThemedClassName } from '@dxos/react-ui';
10
10
  import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
11
11
  import { mx } from '@dxos/ui-theme';
12
12
 
13
- export type MarkdownBlockProps = ThemedClassName<
13
+ export type MarkdownViewProps = ThemedClassName<
14
14
  PropsWithChildren<{
15
15
  content?: string;
16
16
  components?: ReactMarkdownOptions['components'];
@@ -23,7 +23,7 @@ export type MarkdownBlockProps = ThemedClassName<
23
23
  * markdown -> remark -> [mdast -> remark plugins] -> [hast -> rehype plugins] -> components -> react elements.
24
24
  * Consider using @dxos/react-ui-editor.
25
25
  */
26
- export const MarkdownBlock = ({ classNames, children, components, content = '' }: MarkdownBlockProps) => {
26
+ export const MarkdownView = ({ classNames, children, components, content = '' }: MarkdownViewProps) => {
27
27
  return (
28
28
  <div className={mx(classNames)}>
29
29
  <ReactMarkdown remarkPlugins={[remarkGfm]} skipHtml components={{ ...defaultComponents, ...components }}>
@@ -44,6 +44,9 @@ const defaultComponents: ReactMarkdownOptions['components'] = {
44
44
  h3: ({ children }) => {
45
45
  return <h3 className='pt-1 pb-1 text-accent-text text-base'>{children}</h3>;
46
46
  },
47
+ h4: ({ children }) => {
48
+ return <h4 className='pt-1 pb-1 uppercase text-base'>{children}</h4>;
49
+ },
47
50
  blockquote: ({ children, ...props }) => (
48
51
  <blockquote className='my-2 py-2 ps-4 border-l-4 border-accent-text text-accent-text' {...props}>
49
52
  {children}
@@ -63,6 +66,19 @@ const defaultComponents: ReactMarkdownOptions['components'] = {
63
66
  {children}
64
67
  </a>
65
68
  ),
69
+ // Hide broken images: many markdown sources reference remote URLs that
70
+ // 404 or are blocked. Drop the element on load failure rather than
71
+ // leaving the browser's broken-image placeholder.
72
+ //
73
+ // Media URLs (mp4/mp3/etc. or legacy `iframe`-style embeds) are swapped to a
74
+ // native `<video>` / `<audio>` element by {@link MediaPlayer} so playable
75
+ // media in the source document renders inline.
76
+ img: ({ src, alt }) => {
77
+ if (!src) {
78
+ return null;
79
+ }
80
+ return <MediaPlayer src={src} alt={alt} classNames='w-full' />;
81
+ },
66
82
  ol: ({ children, ...props }) => (
67
83
  <ol className='pt-1 pb-1 ps-6 leading-tight list-decimal' {...props}>
68
84
  {children}
@@ -2,4 +2,4 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- export * from './MarkdownBlock';
5
+ export * from './MarkdownView';
package/src/index.ts CHANGED
@@ -2,5 +2,5 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- export * from './MarkdownBlock';
5
+ export * from './MarkdownView';
6
6
  export * from './MarkdownStream';
@@ -1 +0,0 @@
1
- {"version":3,"file":"MarkdownBlock.d.ts","sourceRoot":"","sources":["../../../../src/MarkdownBlock/MarkdownBlock.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,EAAE,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AACtD,OAAsB,EAAE,KAAK,OAAO,IAAI,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAGrF,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAItD,MAAM,MAAM,kBAAkB,GAAG,eAAe,CAC9C,iBAAiB,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,oBAAoB,CAAC,YAAY,CAAC,CAAC;CACjD,CAAC,CACH,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,aAAa,kDAAwD,kBAAkB,sBASnG,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"MarkdownBlock.stories.d.ts","sourceRoot":"","sources":["../../../../src/MarkdownBlock/MarkdownBlock.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAMjE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAIhD,QAAA,MAAM,IAAI;;;;CAI4B,CAAC;eAExB,IAAI;AAEnB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,aAAa,CAAC,CAAC;AA+C5C,eAAO,MAAM,OAAO,EAAE,KAKrB,CAAC"}
@@ -1,2 +0,0 @@
1
- export * from './MarkdownBlock';
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/MarkdownBlock/index.ts"],"names":[],"mappings":"AAIA,cAAc,iBAAiB,CAAC"}