@dxos/react-ui-editor 0.8.2-main.5ca3450 → 0.8.2-main.600d381
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/browser/index.mjs +1591 -1523
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +1383 -1316
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +1591 -1523
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts +1 -1
- package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts.map +1 -1
- package/dist/types/src/{stories/InputMode.stories.d.ts → components/EditorToolbar/EditorToolbar.stories.d.ts} +3 -7
- package/dist/types/src/components/EditorToolbar/EditorToolbar.stories.d.ts.map +1 -0
- package/dist/types/src/components/EditorToolbar/blocks.d.ts +4 -3
- package/dist/types/src/components/EditorToolbar/blocks.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/comment.d.ts +4 -3
- package/dist/types/src/components/EditorToolbar/comment.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/formatting.d.ts +4 -3
- package/dist/types/src/components/EditorToolbar/formatting.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/headings.d.ts +4 -3
- package/dist/types/src/components/EditorToolbar/headings.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/image.d.ts +16 -0
- package/dist/types/src/components/EditorToolbar/image.d.ts.map +1 -0
- package/dist/types/src/components/EditorToolbar/lists.d.ts +4 -3
- package/dist/types/src/components/EditorToolbar/lists.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/search.d.ts +17 -0
- package/dist/types/src/components/EditorToolbar/search.d.ts.map +1 -0
- package/dist/types/src/components/EditorToolbar/util.d.ts +11 -17
- package/dist/types/src/components/EditorToolbar/util.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/view-mode.d.ts +4 -3
- package/dist/types/src/components/EditorToolbar/view-mode.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +0 -1
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/package.json +28 -28
- package/src/components/EditorToolbar/EditorToolbar.stories.tsx +90 -0
- package/src/components/EditorToolbar/EditorToolbar.tsx +30 -31
- package/src/components/EditorToolbar/blocks.ts +27 -6
- package/src/components/EditorToolbar/comment.ts +11 -4
- package/src/components/EditorToolbar/formatting.ts +34 -7
- package/src/components/EditorToolbar/headings.ts +9 -8
- package/src/components/EditorToolbar/image.ts +16 -0
- package/src/components/EditorToolbar/lists.ts +26 -7
- package/src/components/EditorToolbar/search.ts +19 -0
- package/src/components/EditorToolbar/util.ts +14 -14
- package/src/components/EditorToolbar/view-mode.ts +9 -8
- package/src/hooks/index.ts +0 -1
- package/dist/types/src/hooks/useActionHandler.d.ts +0 -4
- package/dist/types/src/hooks/useActionHandler.d.ts.map +0 -1
- package/dist/types/src/stories/InputMode.stories.d.ts.map +0 -1
- package/src/hooks/useActionHandler.ts +0 -12
- package/src/stories/InputMode.stories.tsx +0 -124
@@ -1,14 +1,15 @@
|
|
1
|
+
import { type EditorView } from '@codemirror/view';
|
1
2
|
import { type NodeArg } from '@dxos/app-graph';
|
2
3
|
import { type EditorToolbarState } from './util';
|
3
|
-
export declare const createLists: (state: EditorToolbarState) => {
|
4
|
+
export declare const createLists: (state: EditorToolbarState, getView: () => EditorView) => {
|
4
5
|
nodes: (Readonly<Omit<Readonly<{
|
5
6
|
id: string;
|
6
7
|
type: string;
|
7
8
|
cacheable?: string[];
|
8
|
-
properties: Readonly<import("@dxos/react-ui-menu").MenuActionProperties
|
9
|
+
properties: Readonly<import("@dxos/react-ui-menu").MenuActionProperties>;
|
9
10
|
data: import("@dxos/app-graph").ActionData;
|
10
11
|
}>, "properties"> & {
|
11
|
-
properties: Readonly<import("@dxos/react-ui-menu").MenuActionProperties
|
12
|
+
properties: Readonly<import("@dxos/react-ui-menu").MenuActionProperties>;
|
12
13
|
}> | NodeArg<any>)[];
|
13
14
|
edges: {
|
14
15
|
source: string;
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"lists.d.ts","sourceRoot":"","sources":["../../../../../src/components/EditorToolbar/lists.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAG/C,OAAO,EAA+C,KAAK,kBAAkB,EAAE,MAAM,QAAQ,CAAC;
|
1
|
+
{"version":3,"file":"lists.d.ts","sourceRoot":"","sources":["../../../../../src/components/EditorToolbar/lists.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAG/C,OAAO,EAA+C,KAAK,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAsC9F,eAAO,MAAM,WAAW,GAAI,OAAO,kBAAkB,EAAE,SAAS,MAAM,UAAU;;;;;;;;;;;;;;CAW/E,CAAC"}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import { type EditorView } from '@codemirror/view';
|
2
|
+
export declare const createSearch: (getView: () => EditorView) => {
|
3
|
+
nodes: Readonly<Omit<Readonly<{
|
4
|
+
id: string;
|
5
|
+
type: string;
|
6
|
+
cacheable?: string[];
|
7
|
+
properties: Readonly<import("@dxos/react-ui-menu").MenuActionProperties>;
|
8
|
+
data: import("@dxos/app-graph").ActionData;
|
9
|
+
}>, "properties"> & {
|
10
|
+
properties: Readonly<import("@dxos/react-ui-menu").MenuActionProperties>;
|
11
|
+
}>[];
|
12
|
+
edges: {
|
13
|
+
source: string;
|
14
|
+
target: string;
|
15
|
+
}[];
|
16
|
+
};
|
17
|
+
//# sourceMappingURL=search.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../../../src/components/EditorToolbar/search.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAUnD,eAAO,MAAM,YAAY,GAAI,SAAS,MAAM,UAAU;;;;;;;;;;;;;;CAGpD,CAAC"}
|
@@ -1,7 +1,9 @@
|
|
1
|
+
import { type EditorView } from '@codemirror/view';
|
2
|
+
import { type Action } from '@dxos/app-graph';
|
1
3
|
import { type Live } from '@dxos/live-object';
|
2
|
-
import { type
|
3
|
-
import { type MenuSeparator, type MenuItemGroup, type ToolbarMenuActionGroupProperties, type
|
4
|
-
import type { EditorAction,
|
4
|
+
import { type ThemedClassName } from '@dxos/react-ui';
|
5
|
+
import { type MenuSeparator, type MenuItemGroup, type ToolbarMenuActionGroupProperties, type ActionGraphProps, type MenuActionProperties } from '@dxos/react-ui-menu';
|
6
|
+
import type { EditorAction, EditorViewMode, Formatting } from '../../extensions';
|
5
7
|
export type EditorToolbarState = Formatting & Partial<{
|
6
8
|
comment: boolean;
|
7
9
|
viewMode: EditorViewMode;
|
@@ -13,26 +15,27 @@ export type EditorToolbarFeatureFlags = Partial<{
|
|
13
15
|
formatting: boolean;
|
14
16
|
lists: boolean;
|
15
17
|
blocks: boolean;
|
16
|
-
comment: boolean;
|
17
18
|
search: boolean;
|
18
|
-
|
19
|
+
comment: boolean;
|
20
|
+
image: () => void;
|
21
|
+
viewMode: (mode: EditorViewMode) => void;
|
19
22
|
}>;
|
20
23
|
export type EditorToolbarActionGraphProps = {
|
21
24
|
state: Live<EditorToolbarState>;
|
25
|
+
getView: () => EditorView;
|
22
26
|
customActions?: () => ActionGraphProps;
|
23
|
-
onAction: (action: EditorAction) => void;
|
24
27
|
};
|
25
28
|
export type EditorToolbarProps = ThemedClassName<EditorToolbarActionGraphProps & EditorToolbarFeatureFlags & {
|
26
29
|
attendableId?: string;
|
27
30
|
role?: string;
|
28
31
|
}>;
|
29
32
|
export type EditorToolbarItem = EditorAction | MenuItemGroup | MenuSeparator;
|
30
|
-
export declare const createEditorAction: (
|
33
|
+
export declare const createEditorAction: (id: string, invoke: () => void, properties: Partial<MenuActionProperties>) => Action<MenuActionProperties>;
|
31
34
|
export declare const createEditorActionGroup: (id: string, props: Omit<ToolbarMenuActionGroupProperties, "icon">, icon?: string) => {
|
32
35
|
id: string;
|
33
36
|
type: string;
|
34
37
|
properties: {
|
35
|
-
label: Label;
|
38
|
+
label: import("@dxos/react-ui").Label;
|
36
39
|
value: string | (string & string[]);
|
37
40
|
classNames?: import("@dxos/react-ui-types").ClassNameValue;
|
38
41
|
hidden?: boolean | undefined;
|
@@ -46,13 +49,4 @@ export declare const createEditorActionGroup: (id: string, props: Omit<ToolbarMe
|
|
46
49
|
};
|
47
50
|
data: typeof import("@dxos/app-graph").actionGroupSymbol;
|
48
51
|
};
|
49
|
-
export declare const editorToolbarSearch: Readonly<Omit<Readonly<{
|
50
|
-
id: string;
|
51
|
-
type: string;
|
52
|
-
cacheable?: string[];
|
53
|
-
properties: Readonly<MenuActionProperties & EditorActionPayload>;
|
54
|
-
data: import("@dxos/app-graph").ActionData;
|
55
|
-
}>, "properties"> & {
|
56
|
-
properties: Readonly<MenuActionProperties & EditorActionPayload>;
|
57
|
-
}>;
|
58
52
|
//# sourceMappingURL=util.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../../../src/components/EditorToolbar/util.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../../../src/components/EditorToolbar/util.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnD,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAQ,KAAK,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,gCAAgC,EAGrC,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EAC1B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGjF,MAAM,MAAM,kBAAkB,GAAG,UAAU,GACzC,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,cAAc,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAE9E,eAAO,MAAM,qBAAqB,GAAI,eAAc,OAAO,CAAC,kBAAkB,CAAM,6BAEnF,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,OAAO,CAAC;IAC9C,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAEhB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,QAAQ,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;CAC1C,CAAC,CAAC;AAEH,MAAM,MAAM,6BAA6B,GAAG;IAC1C,KAAK,EAAE,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAChC,OAAO,EAAE,MAAM,UAAU,CAAC;IAE1B,aAAa,CAAC,EAAE,MAAM,gBAAgB,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,eAAe,CAC9C,6BAA6B,GAAG,yBAAyB,GAAG;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CACrG,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,aAAa,GAAG,aAAa,CAAC;AAE7E,eAAO,MAAM,kBAAkB,GAAI,IAAI,MAAM,EAAE,QAAQ,MAAM,IAAI,EAAE,YAAY,OAAO,CAAC,oBAAoB,CAAC,KAE/C,MAAM,CAAC,oBAAoB,CACvF,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,IAAI,MAAM,EACV,OAAO,IAAI,CAAC,gCAAgC,EAAE,MAAM,CAAC,EACrD,OAAO,MAAM;;;;;;;;;;;;;;;;;CACiD,CAAC"}
|
@@ -1,14 +1,15 @@
|
|
1
1
|
import { type NodeArg } from '@dxos/app-graph';
|
2
2
|
import { type EditorToolbarState } from './util';
|
3
|
-
|
3
|
+
import { type EditorViewMode } from '../../extensions';
|
4
|
+
export declare const createViewMode: (state: EditorToolbarState, onViewModeChange: (mode: EditorViewMode) => void) => {
|
4
5
|
nodes: (Readonly<Omit<Readonly<{
|
5
6
|
id: string;
|
6
7
|
type: string;
|
7
8
|
cacheable?: string[];
|
8
|
-
properties: Readonly<import("@dxos/react-ui-menu").MenuActionProperties
|
9
|
+
properties: Readonly<import("@dxos/react-ui-menu").MenuActionProperties>;
|
9
10
|
data: import("@dxos/app-graph").ActionData;
|
10
11
|
}>, "properties"> & {
|
11
|
-
properties: Readonly<import("@dxos/react-ui-menu").MenuActionProperties
|
12
|
+
properties: Readonly<import("@dxos/react-ui-menu").MenuActionProperties>;
|
12
13
|
}> | NodeArg<any>)[];
|
13
14
|
edges: {
|
14
15
|
source: string;
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"view-mode.d.ts","sourceRoot":"","sources":["../../../../../src/components/EditorToolbar/view-mode.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAG/C,OAAO,EAA+C,KAAK,kBAAkB,EAAE,MAAM,QAAQ,CAAC;
|
1
|
+
{"version":3,"file":"view-mode.d.ts","sourceRoot":"","sources":["../../../../../src/components/EditorToolbar/view-mode.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAG/C,OAAO,EAA+C,KAAK,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAC9F,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AA6BvD,eAAO,MAAM,cAAc,GAAI,OAAO,kBAAkB,EAAE,kBAAkB,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI;;;;;;;;;;;;;;CAWzG,CAAC"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/hooks/index.ts"],"names":[],"mappings":"AAIA,cAAc,
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/hooks/index.ts"],"names":[],"mappings":"AAIA,cAAc,iBAAiB,CAAC"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@dxos/react-ui-editor",
|
3
|
-
"version": "0.8.2-main.
|
3
|
+
"version": "0.8.2-main.600d381",
|
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",
|
@@ -57,21 +57,21 @@
|
|
57
57
|
"lodash.merge": "^4.6.2",
|
58
58
|
"lodash.sortby": "^4.7.0",
|
59
59
|
"style-mod": "^4.1.0",
|
60
|
-
"@dxos/
|
61
|
-
"@dxos/
|
62
|
-
"@dxos/context": "0.8.2-main.
|
63
|
-
"@dxos/
|
64
|
-
"@dxos/
|
65
|
-
"@dxos/
|
66
|
-
"@dxos/
|
67
|
-
"@dxos/
|
68
|
-
"@dxos/
|
69
|
-
"@dxos/
|
70
|
-
"@dxos/log": "0.8.2-main.
|
71
|
-
"@dxos/protocols": "0.8.2-main.
|
72
|
-
"@dxos/react-
|
73
|
-
"@dxos/react-
|
74
|
-
"@dxos/util": "0.8.2-main.
|
60
|
+
"@dxos/async": "0.8.2-main.600d381",
|
61
|
+
"@dxos/automerge": "0.8.2-main.600d381",
|
62
|
+
"@dxos/context": "0.8.2-main.600d381",
|
63
|
+
"@dxos/debug": "0.8.2-main.600d381",
|
64
|
+
"@dxos/app-graph": "0.8.2-main.600d381",
|
65
|
+
"@dxos/display-name": "0.8.2-main.600d381",
|
66
|
+
"@dxos/echo-schema": "0.8.2-main.600d381",
|
67
|
+
"@dxos/invariant": "0.8.2-main.600d381",
|
68
|
+
"@dxos/lit-ui": "0.8.2-main.600d381",
|
69
|
+
"@dxos/live-object": "0.8.2-main.600d381",
|
70
|
+
"@dxos/log": "0.8.2-main.600d381",
|
71
|
+
"@dxos/protocols": "0.8.2-main.600d381",
|
72
|
+
"@dxos/react-hooks": "0.8.2-main.600d381",
|
73
|
+
"@dxos/react-ui-menu": "0.8.2-main.600d381",
|
74
|
+
"@dxos/util": "0.8.2-main.600d381"
|
75
75
|
},
|
76
76
|
"devDependencies": {
|
77
77
|
"@phosphor-icons/react": "^2.1.5",
|
@@ -95,24 +95,24 @@
|
|
95
95
|
"vite": "5.4.7",
|
96
96
|
"vite-plugin-top-level-await": "^1.4.1",
|
97
97
|
"vite-plugin-wasm": "^3.3.0",
|
98
|
-
"@dxos/automerge": "0.8.2-main.
|
99
|
-
"@dxos/config": "0.8.2-main.
|
100
|
-
"@dxos/echo-signals": "0.8.2-main.
|
101
|
-
"@dxos/keyboard": "0.8.2-main.
|
102
|
-
"@dxos/random": "0.8.2-main.
|
103
|
-
"@dxos/react-
|
104
|
-
"@dxos/react-ui-theme": "0.8.2-main.
|
105
|
-
"@dxos/react-
|
106
|
-
"@dxos/storybook-utils": "0.8.2-main.
|
98
|
+
"@dxos/automerge": "0.8.2-main.600d381",
|
99
|
+
"@dxos/config": "0.8.2-main.600d381",
|
100
|
+
"@dxos/echo-signals": "0.8.2-main.600d381",
|
101
|
+
"@dxos/keyboard": "0.8.2-main.600d381",
|
102
|
+
"@dxos/random": "0.8.2-main.600d381",
|
103
|
+
"@dxos/react-ui": "0.8.2-main.600d381",
|
104
|
+
"@dxos/react-ui-theme": "0.8.2-main.600d381",
|
105
|
+
"@dxos/react-client": "0.8.2-main.600d381",
|
106
|
+
"@dxos/storybook-utils": "0.8.2-main.600d381"
|
107
107
|
},
|
108
108
|
"peerDependencies": {
|
109
109
|
"@phosphor-icons/react": "^2.1.5",
|
110
110
|
"effect": "^3.13.3",
|
111
111
|
"react": "~18.2.0",
|
112
112
|
"react-dom": "~18.2.0",
|
113
|
-
"@dxos/react-ui": "0.8.2-main.
|
114
|
-
"@dxos/react-
|
115
|
-
"@dxos/react-
|
113
|
+
"@dxos/react-ui-theme": "0.8.2-main.600d381",
|
114
|
+
"@dxos/react-client": "0.8.2-main.600d381",
|
115
|
+
"@dxos/react-ui": "0.8.2-main.600d381"
|
116
116
|
},
|
117
117
|
"publishConfig": {
|
118
118
|
"access": "public"
|
@@ -0,0 +1,90 @@
|
|
1
|
+
//
|
2
|
+
// Copyright 2024 DXOS.org
|
3
|
+
//
|
4
|
+
|
5
|
+
import '@dxos-theme';
|
6
|
+
|
7
|
+
import React, { useCallback, useState } from 'react';
|
8
|
+
|
9
|
+
import { invariant } from '@dxos/invariant';
|
10
|
+
import { useThemeContext } from '@dxos/react-ui';
|
11
|
+
import { attentionSurface, mx } from '@dxos/react-ui-theme';
|
12
|
+
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
13
|
+
|
14
|
+
import { EditorToolbar, useEditorToolbarState } from '..';
|
15
|
+
import {
|
16
|
+
type EditorInputMode,
|
17
|
+
decorateMarkdown,
|
18
|
+
createMarkdownExtensions,
|
19
|
+
formattingKeymap,
|
20
|
+
useFormattingState,
|
21
|
+
createBasicExtensions,
|
22
|
+
createThemeExtensions,
|
23
|
+
InputModeExtensions,
|
24
|
+
type EditorViewMode,
|
25
|
+
} from '../../extensions';
|
26
|
+
import { useTextEditor, type UseTextEditorProps } from '../../hooks';
|
27
|
+
import translations from '../../translations';
|
28
|
+
|
29
|
+
type StoryProps = { placeholder?: string } & UseTextEditorProps;
|
30
|
+
|
31
|
+
const DefaultStory = ({ autoFocus, initialValue, placeholder }: StoryProps) => {
|
32
|
+
const { themeMode } = useThemeContext();
|
33
|
+
const toolbarState = useEditorToolbarState({ viewMode: 'source' });
|
34
|
+
const viewMode = toolbarState.viewMode;
|
35
|
+
const trackFormatting = useFormattingState(toolbarState);
|
36
|
+
// TODO(wittjosiah): Provide way to change the input mode.
|
37
|
+
const [editorInputMode, _setEditorInputMode] = useState<EditorInputMode>('default');
|
38
|
+
const { parentRef, view } = useTextEditor(
|
39
|
+
() => ({
|
40
|
+
autoFocus,
|
41
|
+
initialValue,
|
42
|
+
moveToEndOfLine: true,
|
43
|
+
extensions: [
|
44
|
+
editorInputMode ? InputModeExtensions[editorInputMode] : [],
|
45
|
+
createBasicExtensions({ placeholder, lineWrapping: true, readOnly: viewMode === 'readonly' }),
|
46
|
+
createMarkdownExtensions({ themeMode }),
|
47
|
+
createThemeExtensions({ themeMode, syntaxHighlighting: true }),
|
48
|
+
viewMode === 'source' ? [] : decorateMarkdown(),
|
49
|
+
formattingKeymap(),
|
50
|
+
trackFormatting,
|
51
|
+
],
|
52
|
+
}),
|
53
|
+
[editorInputMode, viewMode, themeMode, placeholder],
|
54
|
+
);
|
55
|
+
|
56
|
+
const getView = useCallback(() => {
|
57
|
+
invariant(view);
|
58
|
+
return view;
|
59
|
+
}, [view]);
|
60
|
+
|
61
|
+
const handleViewModeChange = useCallback((mode: EditorViewMode) => {
|
62
|
+
toolbarState.viewMode = mode;
|
63
|
+
}, []);
|
64
|
+
|
65
|
+
// TODO(marijn): This doesn't update the state on view changes.
|
66
|
+
// Also not sure if view is even guaranteed to exist at this point.
|
67
|
+
return (
|
68
|
+
<div role='none' className={mx('fixed inset-0 flex flex-col')}>
|
69
|
+
{toolbarState && <EditorToolbar state={toolbarState} getView={getView} viewMode={handleViewModeChange} />}
|
70
|
+
<div role='none' className='grow overflow-hidden'>
|
71
|
+
<div className={attentionSurface} ref={parentRef} />
|
72
|
+
</div>
|
73
|
+
</div>
|
74
|
+
);
|
75
|
+
};
|
76
|
+
|
77
|
+
export const Default = {
|
78
|
+
args: {
|
79
|
+
autoFocus: true,
|
80
|
+
placeholder: 'Text...',
|
81
|
+
initialValue: '# Demo\n\nThis is a document.\n\n',
|
82
|
+
},
|
83
|
+
};
|
84
|
+
|
85
|
+
export default {
|
86
|
+
title: 'ui/react-ui-editor/EditorToolbar',
|
87
|
+
render: DefaultStory,
|
88
|
+
decorators: [withTheme, withLayout({ fullscreen: true })],
|
89
|
+
parameters: { translations, layout: 'fullscreen' },
|
90
|
+
};
|
@@ -2,63 +2,60 @@
|
|
2
2
|
// Copyright 2024 DXOS.org
|
3
3
|
//
|
4
4
|
|
5
|
-
import React, { useCallback } from 'react';
|
5
|
+
import React, { memo, useCallback } from 'react';
|
6
6
|
|
7
7
|
import { type NodeArg } from '@dxos/app-graph';
|
8
8
|
import { ElevationProvider } from '@dxos/react-ui';
|
9
|
-
import {
|
10
|
-
type MenuActionHandler,
|
11
|
-
MenuProvider,
|
12
|
-
ToolbarMenu,
|
13
|
-
createGapSeparator,
|
14
|
-
useMenuActions,
|
15
|
-
} from '@dxos/react-ui-menu';
|
9
|
+
import { MenuProvider, ToolbarMenu, createGapSeparator, useMenuActions } from '@dxos/react-ui-menu';
|
16
10
|
import { textBlockWidth } from '@dxos/react-ui-theme';
|
17
11
|
|
18
12
|
import { createBlocks } from './blocks';
|
19
13
|
import { createComment } from './comment';
|
20
14
|
import { createFormatting } from './formatting';
|
21
15
|
import { createHeadings } from './headings';
|
16
|
+
import { createImageUpload } from './image';
|
22
17
|
import { createLists } from './lists';
|
23
|
-
import {
|
24
|
-
|
25
|
-
type EditorToolbarFeatureFlags,
|
26
|
-
type EditorToolbarProps,
|
27
|
-
editorToolbarSearch,
|
28
|
-
} from './util';
|
18
|
+
import { createSearch } from './search';
|
19
|
+
import { type EditorToolbarActionGraphProps, type EditorToolbarFeatureFlags, type EditorToolbarProps } from './util';
|
29
20
|
import { createViewMode } from './view-mode';
|
30
21
|
import { stackItemContentToolbarClassNames } from '../../defaults';
|
31
22
|
|
32
23
|
const createToolbar = ({
|
24
|
+
getView,
|
33
25
|
state,
|
34
26
|
customActions,
|
35
27
|
...features
|
36
|
-
}: EditorToolbarFeatureFlags & Pick<EditorToolbarActionGraphProps, 'state' | 'customActions'>): {
|
28
|
+
}: EditorToolbarFeatureFlags & Pick<EditorToolbarActionGraphProps, 'getView' | 'state' | 'customActions'>): {
|
37
29
|
nodes: NodeArg<any>[];
|
38
30
|
edges: { source: string; target: string }[];
|
39
31
|
} => {
|
40
32
|
const nodes = [];
|
41
33
|
const edges = [];
|
42
34
|
if (features.headings ?? true) {
|
43
|
-
const headings = createHeadings(state);
|
35
|
+
const headings = createHeadings(state, getView);
|
44
36
|
nodes.push(...headings.nodes);
|
45
37
|
edges.push(...headings.edges);
|
46
38
|
}
|
47
39
|
if (features.formatting ?? true) {
|
48
|
-
const formatting = createFormatting(state);
|
40
|
+
const formatting = createFormatting(state, getView);
|
49
41
|
nodes.push(...formatting.nodes);
|
50
42
|
edges.push(...formatting.edges);
|
51
43
|
}
|
52
44
|
if (features.lists ?? true) {
|
53
|
-
const lists = createLists(state);
|
45
|
+
const lists = createLists(state, getView);
|
54
46
|
nodes.push(...lists.nodes);
|
55
47
|
edges.push(...lists.edges);
|
56
48
|
}
|
57
49
|
if (features.blocks ?? true) {
|
58
|
-
const blocks = createBlocks(state);
|
50
|
+
const blocks = createBlocks(state, getView);
|
59
51
|
nodes.push(...blocks.nodes);
|
60
52
|
edges.push(...blocks.edges);
|
61
53
|
}
|
54
|
+
if (features.image) {
|
55
|
+
const image = createImageUpload(features.image);
|
56
|
+
nodes.push(...image.nodes);
|
57
|
+
edges.push(...image.edges);
|
58
|
+
}
|
62
59
|
if (customActions) {
|
63
60
|
const custom = customActions();
|
64
61
|
nodes.push(...custom.nodes);
|
@@ -67,31 +64,33 @@ const createToolbar = ({
|
|
67
64
|
const editorToolbarGap = createGapSeparator();
|
68
65
|
nodes.push(...editorToolbarGap.nodes);
|
69
66
|
edges.push(...editorToolbarGap.edges);
|
70
|
-
if (features.comment
|
71
|
-
const comment = createComment(state);
|
67
|
+
if (features.comment) {
|
68
|
+
const comment = createComment(state, getView);
|
72
69
|
nodes.push(...comment.nodes);
|
73
70
|
edges.push(...comment.edges);
|
74
71
|
}
|
75
72
|
if (features.search ?? true) {
|
76
|
-
|
77
|
-
|
73
|
+
const search = createSearch(getView);
|
74
|
+
nodes.push(...search.nodes);
|
75
|
+
edges.push(...search.edges);
|
78
76
|
}
|
79
|
-
if (features.viewMode
|
80
|
-
const viewMode = createViewMode(state);
|
77
|
+
if (features.viewMode) {
|
78
|
+
const viewMode = createViewMode(state, features.viewMode);
|
81
79
|
nodes.push(...viewMode.nodes);
|
82
80
|
edges.push(...viewMode.edges);
|
83
81
|
}
|
84
82
|
return { nodes, edges };
|
85
83
|
};
|
86
84
|
|
87
|
-
|
85
|
+
// TODO(wittjosiah): Toolbar re-rendering is causing this graph to be recreated and breaking reactivity in some cases.
|
86
|
+
// E.g. for toolbar dropdowns which use active icon, the icon is not updated when the active item changes.
|
87
|
+
// This is currently only happening in the markdown plugin usage and should be reproduced in an editor story.
|
88
|
+
const useEditorToolbarActionGraph = (props: EditorToolbarProps) => {
|
88
89
|
const menuCreator = useCallback(() => createToolbar(props), [props]);
|
89
|
-
|
90
|
-
|
91
|
-
return { resolveGroupItems, onAction: onAction as MenuActionHandler };
|
90
|
+
return useMenuActions(menuCreator);
|
92
91
|
};
|
93
92
|
|
94
|
-
export const EditorToolbar = ({ classNames, attendableId, role, ...props }: EditorToolbarProps) => {
|
93
|
+
export const EditorToolbar = memo(({ classNames, attendableId, role, ...props }: EditorToolbarProps) => {
|
95
94
|
const menuProps = useEditorToolbarActionGraph(props);
|
96
95
|
return (
|
97
96
|
<div role='none' className={stackItemContentToolbarClassNames(role)}>
|
@@ -102,4 +101,4 @@ export const EditorToolbar = ({ classNames, attendableId, role, ...props }: Edit
|
|
102
101
|
</ElevationProvider>
|
103
102
|
</div>
|
104
103
|
);
|
105
|
-
};
|
104
|
+
});
|
@@ -2,11 +2,13 @@
|
|
2
2
|
// Copyright 2025 DXOS.org
|
3
3
|
//
|
4
4
|
|
5
|
+
import { type EditorView } from '@codemirror/view';
|
6
|
+
|
5
7
|
import { type NodeArg } from '@dxos/app-graph';
|
6
8
|
import { type ToolbarMenuActionGroupProperties } from '@dxos/react-ui-menu';
|
7
9
|
|
8
10
|
import { createEditorAction, createEditorActionGroup, type EditorToolbarState } from './util';
|
9
|
-
import {
|
11
|
+
import { removeBlockquote, addBlockquote, removeCodeblock, addCodeblock, insertTable } from '../../extensions';
|
10
12
|
|
11
13
|
const createBlockGroupAction = (value: string) =>
|
12
14
|
createEditorActionGroup('block', {
|
@@ -15,22 +17,41 @@ const createBlockGroupAction = (value: string) =>
|
|
15
17
|
value,
|
16
18
|
} as ToolbarMenuActionGroupProperties);
|
17
19
|
|
18
|
-
const createBlockActions = (value: string, blankLine?: boolean) =>
|
20
|
+
const createBlockActions = (value: string, getView: () => EditorView, blankLine?: boolean) =>
|
19
21
|
Object.entries({
|
20
22
|
blockquote: 'ph--quotes--regular',
|
21
23
|
codeblock: 'ph--code-block--regular',
|
22
24
|
table: 'ph--table--regular',
|
23
25
|
}).map(([type, icon]) => {
|
26
|
+
const checked = type === value;
|
24
27
|
return createEditorAction(
|
25
|
-
|
26
|
-
|
28
|
+
type,
|
29
|
+
() => {
|
30
|
+
const view = getView();
|
31
|
+
if (!view) {
|
32
|
+
return;
|
33
|
+
}
|
34
|
+
|
35
|
+
switch (type) {
|
36
|
+
case 'blockquote':
|
37
|
+
checked ? removeBlockquote(view) : addBlockquote(view);
|
38
|
+
break;
|
39
|
+
case 'codeblock':
|
40
|
+
checked ? removeCodeblock(view) : addCodeblock(view);
|
41
|
+
break;
|
42
|
+
case 'table':
|
43
|
+
insertTable(view);
|
44
|
+
break;
|
45
|
+
}
|
46
|
+
},
|
47
|
+
{ checked, ...(type === 'table' && { disabled: !!blankLine }), icon },
|
27
48
|
);
|
28
49
|
});
|
29
50
|
|
30
|
-
export const createBlocks = (state: EditorToolbarState) => {
|
51
|
+
export const createBlocks = (state: EditorToolbarState, getView: () => EditorView) => {
|
31
52
|
const value = state?.blockQuote ? 'blockquote' : state.blockType ?? '';
|
32
53
|
const blockGroupAction = createBlockGroupAction(value);
|
33
|
-
const blockActions = createBlockActions(value, state.blankLine);
|
54
|
+
const blockActions = createBlockActions(value, getView, state.blankLine);
|
34
55
|
return {
|
35
56
|
nodes: [blockGroupAction as NodeArg<any>, ...blockActions],
|
36
57
|
edges: [
|
@@ -2,9 +2,12 @@
|
|
2
2
|
// Copyright 2025 DXOS.org
|
3
3
|
//
|
4
4
|
|
5
|
+
import { type EditorView } from '@codemirror/view';
|
6
|
+
|
5
7
|
import { type Label } from '@dxos/react-ui';
|
6
8
|
|
7
9
|
import { createEditorAction, type EditorToolbarState } from './util';
|
10
|
+
import { createComment as nativeCreateComment } from '../../extensions';
|
8
11
|
import { translationKey } from '../../translations';
|
9
12
|
|
10
13
|
const commentLabel = (comment?: boolean, selection?: boolean) =>
|
@@ -14,10 +17,14 @@ const commentLabel = (comment?: boolean, selection?: boolean) =>
|
|
14
17
|
? 'select text to comment label'
|
15
18
|
: 'comment label';
|
16
19
|
|
17
|
-
const createCommentAction = (label: Label) =>
|
18
|
-
createEditorAction(
|
20
|
+
const createCommentAction = (label: Label, getView: () => EditorView) =>
|
21
|
+
createEditorAction('comment', () => nativeCreateComment(getView()), {
|
22
|
+
testId: 'editor.toolbar.comment',
|
23
|
+
icon: 'ph--chat-text--regular',
|
24
|
+
label,
|
25
|
+
});
|
19
26
|
|
20
|
-
export const createComment = (state: EditorToolbarState) => ({
|
21
|
-
nodes: [createCommentAction([commentLabel(state.comment, state.selection), { ns: translationKey }])],
|
27
|
+
export const createComment = (state: EditorToolbarState, getView: () => EditorView) => ({
|
28
|
+
nodes: [createCommentAction([commentLabel(state.comment, state.selection), { ns: translationKey }], getView)],
|
22
29
|
edges: [{ source: 'root', target: 'comment' }],
|
23
30
|
});
|
@@ -2,11 +2,13 @@
|
|
2
2
|
// Copyright 2025 DXOS.org
|
3
3
|
//
|
4
4
|
|
5
|
+
import { type EditorView } from '@codemirror/view';
|
6
|
+
|
5
7
|
import { type NodeArg } from '@dxos/app-graph';
|
6
8
|
import { type ToolbarMenuActionGroupProperties } from '@dxos/react-ui-menu';
|
7
9
|
|
8
10
|
import { createEditorAction, createEditorActionGroup, type EditorToolbarState } from './util';
|
9
|
-
import {
|
11
|
+
import { addLink, Inline, removeLink, setStyle, type Formatting } from '../../extensions';
|
10
12
|
|
11
13
|
const formats = {
|
12
14
|
strong: 'ph--text-b--regular',
|
@@ -23,14 +25,39 @@ const createFormattingGroup = (formatting: Formatting) =>
|
|
23
25
|
value: Object.keys(formats).filter((key) => !!formatting[key as keyof Formatting]),
|
24
26
|
} as ToolbarMenuActionGroupProperties);
|
25
27
|
|
26
|
-
const createFormattingActions = (formatting: Formatting) =>
|
27
|
-
Object.entries(formats).map(([type, icon]) =>
|
28
|
-
|
29
|
-
|
28
|
+
const createFormattingActions = (formatting: Formatting, getView: () => EditorView) =>
|
29
|
+
Object.entries(formats).map(([type, icon]) => {
|
30
|
+
const checked = !!formatting[type as keyof Formatting];
|
31
|
+
return createEditorAction(
|
32
|
+
type,
|
33
|
+
() => {
|
34
|
+
const view = getView();
|
35
|
+
if (!view) {
|
36
|
+
return;
|
37
|
+
}
|
38
|
+
|
39
|
+
if (type === 'link') {
|
40
|
+
checked ? removeLink(view) : addLink()(view);
|
41
|
+
return;
|
42
|
+
}
|
43
|
+
|
44
|
+
const inlineType =
|
45
|
+
type === 'strong'
|
46
|
+
? Inline.Strong
|
47
|
+
: type === 'emphasis'
|
48
|
+
? Inline.Emphasis
|
49
|
+
: type === 'strikethrough'
|
50
|
+
? Inline.Strikethrough
|
51
|
+
: Inline.Code;
|
52
|
+
setStyle(inlineType, !checked)(view);
|
53
|
+
},
|
54
|
+
{ checked, icon },
|
55
|
+
);
|
56
|
+
});
|
30
57
|
|
31
|
-
export const createFormatting = (state: EditorToolbarState) => {
|
58
|
+
export const createFormatting = (state: EditorToolbarState, getView: () => EditorView) => {
|
32
59
|
const formattingGroupAction = createFormattingGroup(state);
|
33
|
-
const formattingActions = createFormattingActions(state);
|
60
|
+
const formattingActions = createFormattingActions(state, getView);
|
34
61
|
return {
|
35
62
|
nodes: [formattingGroupAction as NodeArg<any>, ...formattingActions],
|
36
63
|
edges: [
|