@dxos/react-ui-editor 0.6.8-main.046e6cf → 0.6.8-staging.77f93a3

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 (50) hide show
  1. package/dist/lib/browser/index.mjs +290 -293
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/TextEditor.stories.d.ts +5 -2
  5. package/dist/types/src/TextEditor.stories.d.ts.map +1 -1
  6. package/dist/types/src/defaults.d.ts +1 -1
  7. package/dist/types/src/defaults.d.ts.map +1 -1
  8. package/dist/types/src/extensions/doc.d.ts +3 -0
  9. package/dist/types/src/extensions/doc.d.ts.map +1 -1
  10. package/dist/types/src/extensions/factories.d.ts.map +1 -1
  11. package/dist/types/src/extensions/folding.d.ts.map +1 -1
  12. package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
  13. package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -1
  14. package/dist/types/src/extensions/markdown/formatting.d.ts +1 -1
  15. package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
  16. package/dist/types/src/extensions/markdown/highlight.d.ts +2 -1
  17. package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
  18. package/dist/types/src/extensions/markdown/link-paste.d.ts +3 -0
  19. package/dist/types/src/extensions/markdown/link-paste.d.ts.map +1 -1
  20. package/dist/types/src/extensions/markdown/link.d.ts +3 -1
  21. package/dist/types/src/extensions/markdown/link.d.ts.map +1 -1
  22. package/dist/types/src/extensions/state.d.ts +14 -14
  23. package/dist/types/src/extensions/state.d.ts.map +1 -1
  24. package/dist/types/src/extensions/util/react.d.ts +1 -1
  25. package/dist/types/src/extensions/util/react.d.ts.map +1 -1
  26. package/dist/types/src/hooks/useTextEditor.d.ts +5 -3
  27. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
  28. package/dist/types/src/styles/markdown.d.ts +7 -17
  29. package/dist/types/src/styles/markdown.d.ts.map +1 -1
  30. package/dist/types/src/styles/theme.d.ts +2 -1
  31. package/dist/types/src/styles/theme.d.ts.map +1 -1
  32. package/dist/types/src/styles/tokens.d.ts +5 -7
  33. package/dist/types/src/styles/tokens.d.ts.map +1 -1
  34. package/package.json +24 -24
  35. package/src/TextEditor.stories.tsx +40 -27
  36. package/src/defaults.ts +2 -1
  37. package/src/extensions/doc.ts +3 -0
  38. package/src/extensions/factories.ts +3 -2
  39. package/src/extensions/folding.tsx +5 -7
  40. package/src/extensions/markdown/bundle.ts +1 -3
  41. package/src/extensions/markdown/decorate.ts +29 -23
  42. package/src/extensions/markdown/formatting.ts +3 -1
  43. package/src/extensions/markdown/highlight.ts +33 -19
  44. package/src/extensions/markdown/link-paste.ts +3 -0
  45. package/src/extensions/state.ts +41 -35
  46. package/src/extensions/util/react.tsx +3 -4
  47. package/src/hooks/useTextEditor.ts +24 -29
  48. package/src/styles/markdown.ts +17 -40
  49. package/src/styles/theme.ts +42 -49
  50. package/src/styles/tokens.ts +9 -7
@@ -1 +1 @@
1
- {"version":3,"file":"useTextEditor.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useTextEditor.ts"],"names":[],"mappings":"AAIA,OAAO,EAAe,KAAK,iBAAiB,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC1F,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,SAAS,EAMf,MAAM,OAAO,CAAC;AAIf,OAAO,EAAc,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAK5D,MAAM,MAAM,aAAa,GAAG;IAC1B,SAAS,EAAE,SAAS,CAAC,cAAc,CAAC,CAAC;IACrC,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,eAAe,EAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,GAAG;QACtD,QAAQ,EAAE,CAAC,CAAC;QACZ,OAAO,EAAE,oBAAoB,CAAC,cAAc,CAAC,CAAC;KAC/C,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,iBAAiB,EAAE,WAAW,GAAG,YAAY,CAAC,GAAG;IACrF,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAChC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAIF;;GAEG;AACH,eAAO,MAAM,aAAa,WACjB,aAAa,CAAC,kBAAkB,CAAC,SAClC,cAAc,KACnB,aA6HF,CAAC"}
1
+ {"version":3,"file":"useTextEditor.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useTextEditor.ts"],"names":[],"mappings":"AAIA,OAAO,EAAe,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,SAAS,EAMf,MAAM,OAAO,CAAC;AAGf,OAAO,EAAc,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAE5D,OAAO,EAA6D,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhH,MAAM,MAAM,aAAa,GAAG;IAC1B,SAAS,EAAE,SAAS,CAAC,cAAc,CAAC,CAAC;IACrC,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,eAAe,EAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,GAAG;QACtD,QAAQ,EAAE,CAAC,CAAC;QACZ,OAAO,EAAE,oBAAoB,CAAC,cAAc,CAAC,CAAC;KAC/C,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,iBAAiB,EAAE,YAAY,CAAC,GAAG;IACvE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAIF;;GAEG;AACH,eAAO,MAAM,aAAa,WACjB,aAAa,CAAC,kBAAkB,CAAC,SAClC,cAAc,KACnB,aAwHF,CAAC"}
@@ -1,19 +1,9 @@
1
1
  export type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
2
- export declare const heading: (level: HeadingLevel) => string;
3
- export declare const text = "text-neutral-800 dark:text-neutral-200";
4
- export declare const light = "text-neutral-200 dark:text-neutral-800";
5
- export declare const mark: string;
6
- export declare const paragraph = "mlb-1";
7
- export declare const bold = "font-bold";
8
- export declare const italic = "italic";
9
- export declare const strikethrough = "line-through";
10
- export declare const code = "font-mono !no-underline text-neutral-700 dark:text-neutral-300";
11
- export declare const codeMark = "font-mono text-primary-500";
12
- export declare const codeBlock = "mlb-2 font-mono bg-neutral-500/10 p-3 rounded";
13
- export declare const inlineUrl: string;
14
- export declare const blockquote: string;
15
- export declare const horizontalRule = "flex mlb-4 border-b text-neutral-100 dark:text-neutral-900 border-neutral-200 dark:border-neutral-800";
16
- export declare const unorderedList = "mlb-2 grid grid-cols-[min-content_1fr] [&>li:before]:content-[attr(marker)] [&>li:before]:mlb-1 [&>li:before]:mie-2";
17
- export declare const orderedList = "mlb-2 grid grid-cols-[min-content_1fr] [&>li:before]:content-[counters(section,_\".\")_\"._\"] [counter-reset:section] [&>li:before]:mlb-1";
18
- export declare const listItem = "contents before:[counter-increment:section]";
2
+ export declare const theme: {
3
+ mark: string;
4
+ code: string;
5
+ codeMark: string;
6
+ blockquote: string;
7
+ heading: (level: HeadingLevel) => string;
8
+ };
19
9
  //# sourceMappingURL=markdown.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../../../src/styles/markdown.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAcjD,eAAO,MAAM,OAAO,UAAW,YAAY,WAE1C,CAAC;AAEF,eAAO,MAAM,IAAI,2CAA2C,CAAC;AAC7D,eAAO,MAAM,KAAK,2CAA2C,CAAC;AAE9D,eAAO,MAAM,IAAI,QAAmE,CAAC;AAErF,eAAO,MAAM,SAAS,UAAU,CAAC;AAEjC,eAAO,MAAM,IAAI,cAAc,CAAC;AAChC,eAAO,MAAM,MAAM,WAAW,CAAC;AAC/B,eAAO,MAAM,aAAa,iBAAiB,CAAC;AAE5C,eAAO,MAAM,IAAI,mEAAmE,CAAC;AACrF,eAAO,MAAM,QAAQ,+BAA+B,CAAC;AACrD,eAAO,MAAM,SAAS,kDAAkD,CAAC;AAEzE,eAAO,MAAM,SAAS,QAAmB,CAAC;AAE1C,eAAO,MAAM,UAAU,QAAwF,CAAC;AAEhH,eAAO,MAAM,cAAc,0GAC8E,CAAC;AAG1G,eAAO,MAAM,aAAa,wHAC6F,CAAC;AACxH,eAAO,MAAM,WAAW,+IACkH,CAAC;AAE3I,eAAO,MAAM,QAAQ,gDAAgD,CAAC"}
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../../../src/styles/markdown.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAcjD,eAAO,MAAM,KAAK;;;;;qBAMC,YAAY;CAG9B,CAAC"}
@@ -1,4 +1,5 @@
1
- import { type ThemeStyles } from './tokens';
1
+ import { type StyleSpec } from 'style-mod';
2
+ export type ThemeStyles = Record<string, StyleSpec>;
2
3
  /**
3
4
  * Minimal styles.
4
5
  * https://codemirror.net/examples/styling
@@ -1 +1 @@
1
- {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../../src/styles/theme.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,WAAW,EAAU,MAAM,UAAU,CAAC;AAKpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,YAAY,EAAE,WAkQ1B,CAAC"}
1
+ {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../../src/styles/theme.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAI3C,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAMpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,YAAY,EAAE,WAwP1B,CAAC"}
@@ -1,8 +1,6 @@
1
- import type { StyleSpec } from 'style-mod';
2
- import { type TailwindConfig } from '@dxos/react-ui-theme';
3
- export type ThemeStyles = {
4
- [selector: string]: StyleSpec;
5
- };
6
- export declare const tokens: TailwindConfig['theme'];
7
- export declare const getToken: (path: string, defaultValue?: any) => any;
1
+ /**
2
+ * @deprecated
3
+ * Replace with CSS vars.
4
+ */
5
+ export declare const getToken: (path: string, defaultValue?: string | string[]) => string;
8
6
  //# sourceMappingURL=tokens.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../../../src/styles/tokens.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3E,MAAM,MAAM,WAAW,GAAG;IACxB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE,cAAc,CAAC,OAAO,CAA4B,CAAC;AAExE,eAAO,MAAM,QAAQ,SAAU,MAAM,iBAAgB,GAAG,QAAgD,CAAC"}
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../../../src/styles/tokens.ts"],"names":[],"mappings":"AAUA;;;GAGG;AACH,eAAO,MAAM,QAAQ,SAAU,MAAM,iBAAiB,MAAM,GAAG,MAAM,EAAE,KAAG,MAGzE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-editor",
3
- "version": "0.6.8-main.046e6cf",
3
+ "version": "0.6.8-staging.77f93a3",
4
4
  "description": "Document editing experience within a DXOS shell.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -46,19 +46,19 @@
46
46
  "lodash.sortby": "^4.7.0",
47
47
  "react-dropzone": "^14.2.3",
48
48
  "style-mod": "^4.1.0",
49
- "@dxos/async": "0.6.8-main.046e6cf",
50
- "@dxos/debug": "0.6.8-main.046e6cf",
51
- "@dxos/automerge": "0.6.8-main.046e6cf",
52
- "@dxos/display-name": "0.6.8-main.046e6cf",
53
- "@dxos/echo-schema": "0.6.8-main.046e6cf",
54
- "@dxos/invariant": "0.6.8-main.046e6cf",
55
- "@dxos/context": "0.6.8-main.046e6cf",
56
- "@dxos/log": "0.6.8-main.046e6cf",
57
- "@dxos/protocols": "0.6.8-main.046e6cf",
58
- "@dxos/react-async": "0.6.8-main.046e6cf",
59
- "@dxos/react-ui": "0.6.8-main.046e6cf",
60
- "@dxos/react-ui-theme": "0.6.8-main.046e6cf",
61
- "@dxos/util": "0.6.8-main.046e6cf"
49
+ "@dxos/async": "0.6.8-staging.77f93a3",
50
+ "@dxos/context": "0.6.8-staging.77f93a3",
51
+ "@dxos/automerge": "0.6.8-staging.77f93a3",
52
+ "@dxos/debug": "0.6.8-staging.77f93a3",
53
+ "@dxos/echo-schema": "0.6.8-staging.77f93a3",
54
+ "@dxos/display-name": "0.6.8-staging.77f93a3",
55
+ "@dxos/invariant": "0.6.8-staging.77f93a3",
56
+ "@dxos/log": "0.6.8-staging.77f93a3",
57
+ "@dxos/protocols": "0.6.8-staging.77f93a3",
58
+ "@dxos/react-ui": "0.6.8-staging.77f93a3",
59
+ "@dxos/react-async": "0.6.8-staging.77f93a3",
60
+ "@dxos/util": "0.6.8-staging.77f93a3",
61
+ "@dxos/react-ui-theme": "0.6.8-staging.77f93a3"
62
62
  },
63
63
  "devDependencies": {
64
64
  "@phosphor-icons/react": "^2.1.5",
@@ -83,21 +83,21 @@
83
83
  "vite-plugin-top-level-await": "^1.4.1",
84
84
  "vite-plugin-wasm": "^3.3.0",
85
85
  "vitest": "^1.5.0",
86
- "@dxos/automerge": "0.6.8-main.046e6cf",
87
- "@dxos/config": "0.6.8-main.046e6cf",
88
- "@dxos/echo-typegen": "0.6.8-main.046e6cf",
89
- "@dxos/echo-signals": "0.6.8-main.046e6cf",
90
- "@dxos/keyboard": "0.6.8-main.046e6cf",
91
- "@dxos/random": "0.6.8-main.046e6cf",
92
- "@dxos/react-client": "0.6.8-main.046e6cf",
93
- "@dxos/react-ui": "0.6.8-main.046e6cf",
94
- "@dxos/storybook-utils": "0.6.8-main.046e6cf"
86
+ "@dxos/config": "0.6.8-staging.77f93a3",
87
+ "@dxos/automerge": "0.6.8-staging.77f93a3",
88
+ "@dxos/echo-typegen": "0.6.8-staging.77f93a3",
89
+ "@dxos/echo-signals": "0.6.8-staging.77f93a3",
90
+ "@dxos/keyboard": "0.6.8-staging.77f93a3",
91
+ "@dxos/random": "0.6.8-staging.77f93a3",
92
+ "@dxos/react-client": "0.6.8-staging.77f93a3",
93
+ "@dxos/react-ui": "0.6.8-staging.77f93a3",
94
+ "@dxos/storybook-utils": "0.6.8-staging.77f93a3"
95
95
  },
96
96
  "peerDependencies": {
97
97
  "@phosphor-icons/react": "^2.1.5",
98
98
  "react": "^18.0.0",
99
99
  "react-dom": "^18.0.0",
100
- "@dxos/react-client": "0.6.8-main.046e6cf"
100
+ "@dxos/react-client": "0.6.8-staging.77f93a3"
101
101
  },
102
102
  "publishConfig": {
103
103
  "access": "public"
@@ -17,11 +17,11 @@ import { PublicKey } from '@dxos/keys';
17
17
  import { log } from '@dxos/log';
18
18
  import { faker } from '@dxos/random';
19
19
  import { createDocAccessor, createEchoObject } from '@dxos/react-client/echo';
20
- import { Button, DensityProvider, Input, ThemeProvider, useThemeContext } from '@dxos/react-ui';
21
- import { baseSurface, defaultTx, mx, getSize } from '@dxos/react-ui-theme';
20
+ import { Button, DensityProvider, Input, useThemeContext } from '@dxos/react-ui';
21
+ import { baseSurface, mx, getSize } from '@dxos/react-ui-theme';
22
22
  import { withFullscreen, withTheme } from '@dxos/storybook-utils';
23
23
 
24
- import { editorContent } from './defaults';
24
+ import { editorContent, editorGutter } from './defaults';
25
25
  import {
26
26
  InputModeExtensions,
27
27
  annotations,
@@ -47,11 +47,11 @@ import {
47
47
  table,
48
48
  typewriter,
49
49
  type CommandAction,
50
- type CommandOptions,
51
50
  type Comment,
52
51
  type CommentsOptions,
53
- type SelectionState,
52
+ type EditorSelectionState,
54
53
  } from './extensions';
54
+ import { renderRoot } from './extensions/util';
55
55
  import { useTextEditor, type UseTextEditorProps } from './hooks';
56
56
  import translations from './translations';
57
57
 
@@ -153,17 +153,19 @@ const content = {
153
153
  ...[1, 2, 3, 4, 5, 6].map((level) => ['#'.repeat(level) + ` Heading ${level}`, faker.lorem.sentences(), '']).flat(),
154
154
  ),
155
155
 
156
- formatting: str('### Formatting', 'This this is **bold**, ~~strikethrough~~, _italic_, and `f(INLINE)`.'),
156
+ formatting: str('### Formatting', '', 'This this is **bold**, ~~strikethrough~~, _italic_, and `f(INLINE)`.', ''),
157
157
 
158
158
  blockquotes: str(
159
159
  '### Blockquotes',
160
+ '',
160
161
  '> This is a block quote.',
161
162
  '',
162
163
  '> This is a long wrapping block quote. Neque reiciendis ullam quae error labore sit, at, et, nulla, aut at nostrum omnis quas nostrum, at consectetur vitae eos asperiores non omnis ullam in beatae at vitae deserunt asperiores sapiente.',
163
164
  '',
164
- '> This is',
165
- '> a multi-line',
165
+ '> This is ...',
166
+ '> ... a multi-line ...',
166
167
  '> block quote.',
168
+ '',
167
169
  ),
168
170
 
169
171
  paragraphs: str(...faker.helpers.multiple(() => [faker.lorem.paragraph(), ''], { count: 3 }).flat()),
@@ -264,7 +266,7 @@ type StoryProps = {
264
266
  text?: string;
265
267
  readonly?: boolean;
266
268
  placeholder?: string;
267
- } & Pick<UseTextEditorProps, 'selection' | 'extensions'>;
269
+ } & Pick<UseTextEditorProps, 'scrollTo' | 'selection' | 'extensions'>;
268
270
 
269
271
  const Story = ({
270
272
  id = 'editor-' + PublicKey.random().toHex().slice(0, 8),
@@ -272,6 +274,7 @@ const Story = ({
272
274
  extensions,
273
275
  readonly,
274
276
  placeholder = 'New document.',
277
+ scrollTo,
275
278
  selection,
276
279
  }: StoryProps) => {
277
280
  const [object] = useState(createEchoObject(create(Expando, { content: text ?? '' })));
@@ -294,6 +297,7 @@ const Story = ({
294
297
  }),
295
298
  extensions || [],
296
299
  ],
300
+ scrollTo,
297
301
  selection,
298
302
  }),
299
303
  [object, extensions, themeMode],
@@ -313,13 +317,25 @@ const defaults = [
313
317
  autocomplete({
314
318
  onSearch: (text) => links.filter(({ label }) => label.toLowerCase().includes(text.toLowerCase())),
315
319
  }),
316
- decorateMarkdown({ renderLinkButton, selectionChangeDelay: 100, numberedHeadings: { from: 1, to: 4 } }),
320
+ decorateMarkdown({ renderLinkButton, selectionChangeDelay: 100 }),
317
321
  formattingKeymap(),
318
322
  linkTooltip(renderLinkTooltip),
319
323
  ];
320
324
 
321
325
  export const Default = {
322
- render: () => <Story text={text} extensions={defaults} />,
326
+ render: () => <Story text={text} extensions={defaults} selection={{ anchor: 99, head: 110 }} />,
327
+ };
328
+
329
+ export const ScrollTo = {
330
+ render: () => {
331
+ // NOTE: Selection won't appear if text is reformatted.
332
+ const word = 'Scroll to here...';
333
+ const text = str('# Scroll To', longText, '', word, '', longText);
334
+ const idx = text.indexOf(word);
335
+ return (
336
+ <Story text={text} extensions={defaults} scrollTo={idx} selection={{ anchor: idx, head: idx + word.length }} />
337
+ );
338
+ },
323
339
  };
324
340
 
325
341
  export const Readonly = {
@@ -335,10 +351,10 @@ export const NoExtensions = {
335
351
  };
336
352
 
337
353
  export const Folding = {
338
- render: () => <Story text={text} extensions={[folding()]} />,
354
+ render: () => <Story text={text} extensions={[editorGutter, folding()]} />,
339
355
  };
340
356
 
341
- const large = faker.helpers.multiple(() => faker.lorem.paragraph({ min: 8, max: 16 }), { count: 20 }).join('\n\n');
357
+ const longText = faker.helpers.multiple(() => faker.lorem.paragraph({ min: 8, max: 16 }), { count: 20 }).join('\n\n');
342
358
 
343
359
  const largeWithImages = faker.helpers
344
360
  .multiple(() => [faker.lorem.paragraph({ min: 12, max: 16 }), img], { count: 20 })
@@ -355,12 +371,12 @@ export const Headings = {
355
371
  render: () => <Story text={headings} extensions={decorateMarkdown({ numberedHeadings: { from: 2, to: 4 } })} />,
356
372
  };
357
373
 
358
- const global = new Map<string, SelectionState>();
374
+ const global = new Map<string, EditorSelectionState>();
359
375
 
360
376
  export const Scrolling = {
361
377
  render: () => (
362
378
  <Story
363
- text={str('# Large Document', '', large)}
379
+ text={str('# Large Document', '', longText)}
364
380
  extensions={state({
365
381
  setState: (id, state) => global.set(id, state),
366
382
  getState: (id) => global.get(id),
@@ -489,21 +505,18 @@ const CommandDialog: FC<{ onClose: (action?: CommandAction) => void }> = ({ onCl
489
505
  );
490
506
  };
491
507
 
492
- const renderCommandDialog: CommandOptions['onRender'] = (el, onClose) => {
493
- createRoot(el).render(
494
- <StrictMode>
495
- <ThemeProvider tx={defaultTx}>
496
- <CommandDialog onClose={onClose} />
497
- </ThemeProvider>
498
- </StrictMode>,
499
- );
500
- };
501
-
502
508
  export const Command = {
503
509
  render: () => (
504
510
  <Story
505
511
  text={str('# Command', '')}
506
- extensions={[command({ onRender: renderCommandDialog, onHint: () => 'Press / for commands.' })]}
512
+ extensions={[
513
+ command({
514
+ onRender: (el, onClose) => {
515
+ renderRoot(el, <CommandDialog onClose={onClose} />);
516
+ },
517
+ onHint: () => 'Press / for commands.',
518
+ }),
519
+ ]}
507
520
  />
508
521
  ),
509
522
  };
@@ -558,7 +571,7 @@ export const Vim = {
558
571
  };
559
572
 
560
573
  export const Annotations = {
561
- render: () => <Story text={str('# Annotations', '', large)} extensions={[annotations({ match: /volup/gi })]} />,
574
+ render: () => <Story text={str('# Annotations', '', longText)} extensions={[annotations({ match: /volup/gi })]} />,
562
575
  };
563
576
 
564
577
  export const DND = {
package/src/defaults.ts CHANGED
@@ -11,7 +11,7 @@ export { getToken } from './styles';
11
11
  * 40rem = 640px. Corresponds to initial plank width (Google docs, Stashpad, etc.)
12
12
  * 50rem = 800px. Maximum content width for solo mode.
13
13
  */
14
- export const editorContent = '!mt-[16px] !mli-auto w-full max-w-[min(50rem,100%-4rem)]';
14
+ export const editorContent = '!mt-[16px] !mb-[32px] !mli-auto w-full max-w-[min(50rem,100%-4rem)]';
15
15
 
16
16
  export const editorWithToolbarLayout =
17
17
  'grid grid-cols-1 grid-rows-[min-content_1fr] data-[toolbar=disabled]:grid-rows-[1fr] justify-center content-start overflow-hidden';
@@ -20,6 +20,7 @@ export const editorGutter = EditorView.baseTheme({
20
20
  '.cm-gutters': {
21
21
  // Match margin from content.
22
22
  marginTop: '16px',
23
+ marginBottom: '16px',
23
24
  // Inside within content margin.
24
25
  marginRight: '-32px',
25
26
  width: '32px',
@@ -6,6 +6,9 @@ import { Facet } from '@codemirror/state';
6
6
 
7
7
  import { invariant } from '@dxos/invariant';
8
8
 
9
+ /**
10
+ * Currently edited document id as FQ string.
11
+ */
9
12
  export const documentId = Facet.define<string, string>({
10
13
  combine: (providers) => {
11
14
  invariant(providers.length <= 1);
@@ -3,7 +3,7 @@
3
3
  //
4
4
 
5
5
  import { closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete';
6
- import { defaultKeymap, history, historyKeymap, indentWithTab, standardKeymap } from '@codemirror/commands';
6
+ import { defaultKeymap, history, historyKeymap, standardKeymap } from '@codemirror/commands';
7
7
  import { bracketMatching } from '@codemirror/language';
8
8
  import { searchKeymap } from '@codemirror/search';
9
9
  import { EditorState, type Extension } from '@codemirror/state';
@@ -109,8 +109,9 @@ export const createBasicExtensions = (_props?: BasicExtensionsOptions): Extensio
109
109
  keymap.of(
110
110
  [
111
111
  ...((props.keymap && keymaps[props.keymap]) ?? []),
112
+ // NOTE: Tab configured by markdown extension.
112
113
  // https://codemirror.net/docs/ref/#commands.indentWithTab
113
- ...(props.indentWithTab ? [indentWithTab] : []),
114
+ // ...(props.indentWithTab ? [indentWithTab] : []),
114
115
  // https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
115
116
  ...(props.closeBrackets ? closeBracketsKeymap : []),
116
117
  // https://codemirror.net/docs/ref/#commands.historyKeymap
@@ -6,8 +6,7 @@ import { codeFolding, foldGutter } from '@codemirror/language';
6
6
  import { type Extension } from '@codemirror/state';
7
7
  import React from 'react';
8
8
 
9
- import { ThemeProvider } from '@dxos/react-ui';
10
- import { defaultTx, getSize, mx } from '@dxos/react-ui-theme';
9
+ import { getSize, mx } from '@dxos/react-ui-theme';
11
10
 
12
11
  import { renderRoot } from './util';
13
12
 
@@ -23,11 +22,10 @@ export const folding = (_props: FoldingOptions = {}): Extension => [
23
22
  foldGutter({
24
23
  markerDOM: (open) => {
25
24
  return renderRoot(
26
- <ThemeProvider tx={defaultTx}>
27
- <svg className={mx(getSize(3), 'm-3 cursor-pointer', open && 'rotate-90')}>
28
- <use href={'/icons.svg#ph--caret-right--regular'} />
29
- </svg>
30
- </ThemeProvider>,
25
+ document.createElement('div'),
26
+ <svg className={mx(getSize(3), 'm-3 cursor-pointer', open && 'rotate-90')}>
27
+ <use href={'/icons.svg#ph--caret-right--regular'} />
28
+ </svg>,
31
29
  );
32
30
  },
33
31
  }),
@@ -15,7 +15,6 @@ import { keymap } from '@codemirror/view';
15
15
  import { type ThemeMode } from '@dxos/react-ui';
16
16
 
17
17
  import { markdownHighlightStyle, markdownTagsExtensions } from './highlight';
18
- import { linkPastePlugin } from './link-paste';
19
18
 
20
19
  export type MarkdownBundleOptions = {
21
20
  themeMode?: ThemeMode;
@@ -58,9 +57,8 @@ export const createMarkdownExtensions = ({ themeMode }: MarkdownBundleOptions =
58
57
  // Custom styles.
59
58
  syntaxHighlighting(markdownHighlightStyle()),
60
59
 
61
- linkPastePlugin,
62
-
63
60
  keymap.of([
61
+ // TODO(burdon): Indent by 4 if in task list.
64
62
  // https://codemirror.net/docs/ref/#commands.indentWithTab
65
63
  indentWithTab,
66
64
 
@@ -11,8 +11,9 @@ import { invariant } from '@dxos/invariant';
11
11
  import { mx } from '@dxos/react-ui-theme';
12
12
 
13
13
  import { image } from './image';
14
+ import { linkPastePlugin } from './link-paste';
14
15
  import { table } from './table';
15
- import { getToken, heading, type HeadingLevel } from '../../styles';
16
+ import { getToken, theme, type HeadingLevel } from '../../styles';
16
17
  import { wrapWithCatch } from '../util';
17
18
 
18
19
  //
@@ -201,28 +202,34 @@ const buildDecorations = (view: EditorView, options: DecorateOptions, focus: boo
201
202
  }
202
203
 
203
204
  const editing = editingRange(state, node, focus);
204
- if (!editing) {
205
- const mark = node.node.firstChild!;
206
- if (mark?.name === 'HeaderMark') {
207
- let text = view.state.sliceDoc(mark.to, node.to).trim();
208
- const { from, to } = options.numberedHeadings ?? {};
209
- if (from && (!to || level <= to)) {
210
- const num = headers
205
+ if (editing) {
206
+ break;
207
+ }
208
+
209
+ const mark = node.node.firstChild!;
210
+ if (mark?.name === 'HeaderMark') {
211
+ const { from, to = 6 } = options.numberedHeadings ?? {};
212
+ const text = view.state.sliceDoc(node.from, node.to);
213
+ const len = text.match(/[#\s]+/)![0].length;
214
+ if (!from || level < from || level > to) {
215
+ atomicDeco.add(mark.from, mark.from + len, hide);
216
+ } else {
217
+ // TODO(burdon): Number format/style.
218
+ const num =
219
+ headers
211
220
  .slice(from - 1)
212
221
  .map((level) => level?.number ?? 0)
213
- .join('.');
214
- if (num.length) {
215
- text = `${num} ${text}`;
216
- }
222
+ .join('.') + ' ';
223
+
224
+ if (num.length) {
225
+ atomicDeco.add(
226
+ mark.from,
227
+ mark.from + len,
228
+ Decoration.replace({
229
+ widget: new TextWidget(num, theme.heading(level)),
230
+ }),
231
+ );
217
232
  }
218
-
219
- deco.add(
220
- node.from,
221
- node.to,
222
- Decoration.replace({
223
- widget: new TextWidget(text, heading(level)),
224
- }),
225
- );
226
233
  }
227
234
  }
228
235
 
@@ -271,7 +278,6 @@ const buildDecorations = (view: EditorView, options: DecorateOptions, focus: boo
271
278
  // const mark = node.node.firstChild!;
272
279
  // console.log(mark?.name);
273
280
  // if (mark?.name === 'ListMark') {}
274
-
275
281
  break;
276
282
  }
277
283
 
@@ -515,6 +521,7 @@ export const decorateMarkdown = (options: DecorateOptions = {}) => {
515
521
  },
516
522
  ),
517
523
  formattingStyles,
524
+ linkPastePlugin,
518
525
  image(),
519
526
  table(),
520
527
  ];
@@ -522,7 +529,7 @@ export const decorateMarkdown = (options: DecorateOptions = {}) => {
522
529
 
523
530
  const formattingStyles = EditorView.baseTheme({
524
531
  '& .cm-code': {
525
- fontFamily: getToken('fontFamily.mono', []).join(','),
532
+ fontFamily: getToken('fontFamily.mono'),
526
533
  },
527
534
 
528
535
  '& .cm-codeblock-line': {
@@ -579,7 +586,6 @@ const formattingStyles = EditorView.baseTheme({
579
586
  '& .cm-list-mark': {
580
587
  display: 'inline-block',
581
588
  textAlign: 'right',
582
- color: getToken('extend.colors.neutral.500'),
583
589
  fontVariant: 'tabular-nums',
584
590
  },
585
591
  '& .cm-list-mark-bullet': {
@@ -3,6 +3,7 @@
3
3
  //
4
4
 
5
5
  import { snippet } from '@codemirror/autocomplete';
6
+ import { indentWithTab } from '@codemirror/commands';
6
7
  import { syntaxTree } from '@codemirror/language';
7
8
  import {
8
9
  type Extension,
@@ -1015,8 +1016,9 @@ export const toggleCodeblock: StateCommand = (target) => {
1015
1016
  //
1016
1017
 
1017
1018
  export type FormattingOptions = {};
1019
+ indentWithTab;
1018
1020
 
1019
- export const formattingKeymap = (options: FormattingOptions = {}): Extension => {
1021
+ export const formattingKeymap = (_options: FormattingOptions = {}): Extension => {
1020
1022
  return [
1021
1023
  keymap.of([
1022
1024
  {
@@ -7,7 +7,7 @@ import { HighlightStyle } from '@codemirror/language';
7
7
  import { tags, styleTags, Tag } from '@lezer/highlight';
8
8
  import { type MarkdownConfig, Table } from '@lezer/markdown';
9
9
 
10
- import { blockquote, bold, code, codeMark, getToken, heading, italic, mark, strikethrough } from '../../styles';
10
+ import { getToken, theme } from '../../styles';
11
11
 
12
12
  /**
13
13
  * Custom tags defined and processed by the GFM lezer extension.
@@ -49,6 +49,8 @@ export const markdownTagsExtensions: MarkdownConfig[] = [
49
49
  },
50
50
  ];
51
51
 
52
+ export type HighlightOptions = {};
53
+
52
54
  /**
53
55
  * Styling based on `lezer` parser tags.
54
56
  * https://codemirror.net/examples/styling
@@ -60,7 +62,7 @@ export const markdownTagsExtensions: MarkdownConfig[] = [
60
62
  * - https://github.com/codemirror/language/blob/main/src/highlight.ts#L194
61
63
  * - https://github.com/codemirror/theme-one-dark/blob/main/src/one-dark.ts#L115
62
64
  */
63
- export const markdownHighlightStyle = (readonly?: boolean) => {
65
+ export const markdownHighlightStyle = (_options: HighlightOptions = {}) => {
64
66
  return HighlightStyle.define(
65
67
  [
66
68
  {
@@ -99,6 +101,7 @@ export const markdownHighlightStyle = (readonly?: boolean) => {
99
101
  tags.inserted,
100
102
  tags.invalid,
101
103
  ],
104
+ // TODO(burdon): Explain.
102
105
  color: 'inherit !important',
103
106
  },
104
107
 
@@ -111,38 +114,49 @@ export const markdownHighlightStyle = (readonly?: boolean) => {
111
114
  markdownTags.LinkReference,
112
115
  markdownTags.ListMark,
113
116
  ],
114
- class: mark,
117
+ class: theme.mark,
115
118
  },
116
119
 
117
120
  // Markdown marks.
118
121
  {
119
- tag: [markdownTags.CodeMark, markdownTags.HeaderMark, markdownTags.QuoteMark, markdownTags.EmphasisMark],
120
- class: mark,
122
+ tag: [
123
+ //
124
+ markdownTags.CodeMark,
125
+ markdownTags.HeaderMark,
126
+ markdownTags.QuoteMark,
127
+ markdownTags.EmphasisMark,
128
+ ],
129
+ class: theme.mark,
121
130
  },
122
131
 
123
132
  // E.g., code block language (after ```).
124
133
  {
125
- tag: [tags.function(tags.variableName), tags.labelName],
126
- class: codeMark,
134
+ tag: [
135
+ //
136
+ tags.function(tags.variableName),
137
+ tags.labelName,
138
+ ],
139
+ class: theme.codeMark,
127
140
  },
128
141
 
142
+ // Fonts.
129
143
  {
130
144
  tag: [tags.monospace],
131
145
  class: 'font-mono',
132
146
  },
133
147
 
134
148
  // Headings.
135
- { tag: tags.heading1, class: heading(1) },
136
- { tag: tags.heading2, class: heading(2) },
137
- { tag: tags.heading3, class: heading(3) },
138
- { tag: tags.heading4, class: heading(4) },
139
- { tag: tags.heading5, class: heading(5) },
140
- { tag: tags.heading6, class: heading(6) },
149
+ { tag: tags.heading1, class: theme.heading(1) },
150
+ { tag: tags.heading2, class: theme.heading(2) },
151
+ { tag: tags.heading3, class: theme.heading(3) },
152
+ { tag: tags.heading4, class: theme.heading(4) },
153
+ { tag: tags.heading5, class: theme.heading(5) },
154
+ { tag: tags.heading6, class: theme.heading(6) },
141
155
 
142
156
  // Emphasis.
143
- { tag: tags.emphasis, class: italic },
144
- { tag: tags.strong, class: bold },
145
- { tag: tags.strikethrough, class: strikethrough },
157
+ { tag: tags.emphasis, class: 'italic' },
158
+ { tag: tags.strong, class: 'font-bold' },
159
+ { tag: tags.strikethrough, class: 'line-through' },
146
160
 
147
161
  // NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
148
162
  // However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
@@ -151,12 +165,12 @@ export const markdownHighlightStyle = (readonly?: boolean) => {
151
165
  // IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.
152
166
  {
153
167
  tag: [markdownTags.CodeText, markdownTags.InlineCode],
154
- class: code,
168
+ class: theme.code,
155
169
  },
156
170
 
157
171
  {
158
172
  tag: [markdownTags.QuoteMark],
159
- class: blockquote,
173
+ class: theme.blockquote,
160
174
  },
161
175
 
162
176
  {
@@ -167,7 +181,7 @@ export const markdownHighlightStyle = (readonly?: boolean) => {
167
181
  {
168
182
  scope: markdownLanguage,
169
183
  all: {
170
- fontFamily: getToken('fontFamily.body', []).join(','),
184
+ fontFamily: getToken('fontFamily.body'),
171
185
  },
172
186
  },
173
187
  );