@dxos/react-ui-editor 0.8.4-main.9735255 → 0.8.4-main.9be5663bfe

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 (94) hide show
  1. package/dist/lib/browser/index.mjs +310 -388
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +310 -388
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/components/Editor/Editor.d.ts +9 -15
  8. package/dist/types/src/components/Editor/Editor.d.ts.map +1 -1
  9. package/dist/types/src/components/Editor/Editor.stories.d.ts.map +1 -1
  10. package/dist/types/src/components/EditorContent/EditorContent.d.ts.map +1 -1
  11. package/dist/types/src/components/EditorMenuProvider/EditorMenuProvider.d.ts +1 -3
  12. package/dist/types/src/components/EditorMenuProvider/EditorMenuProvider.d.ts.map +1 -1
  13. package/dist/types/src/components/EditorMenuProvider/menu-presets.d.ts.map +1 -1
  14. package/dist/types/src/components/EditorMenuProvider/useEditorMenu.d.ts.map +1 -1
  15. package/dist/types/src/components/EditorPreviewProvider/EditorPreviewProvider.d.ts.map +1 -1
  16. package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts.map +1 -1
  17. package/dist/types/src/components/EditorToolbar/blocks.d.ts +3 -17
  18. package/dist/types/src/components/EditorToolbar/blocks.d.ts.map +1 -1
  19. package/dist/types/src/components/EditorToolbar/formatting.d.ts +3 -17
  20. package/dist/types/src/components/EditorToolbar/formatting.d.ts.map +1 -1
  21. package/dist/types/src/components/EditorToolbar/headings.d.ts +3 -17
  22. package/dist/types/src/components/EditorToolbar/headings.d.ts.map +1 -1
  23. package/dist/types/src/components/EditorToolbar/image.d.ts +3 -8
  24. package/dist/types/src/components/EditorToolbar/image.d.ts.map +1 -1
  25. package/dist/types/src/components/EditorToolbar/index.d.ts +0 -1
  26. package/dist/types/src/components/EditorToolbar/index.d.ts.map +1 -1
  27. package/dist/types/src/components/EditorToolbar/lists.d.ts +6 -0
  28. package/dist/types/src/components/EditorToolbar/lists.d.ts.map +1 -0
  29. package/dist/types/src/components/EditorToolbar/search.d.ts +3 -8
  30. package/dist/types/src/components/EditorToolbar/search.d.ts.map +1 -1
  31. package/dist/types/src/components/EditorToolbar/view-mode.d.ts +3 -17
  32. package/dist/types/src/components/EditorToolbar/view-mode.d.ts.map +1 -1
  33. package/dist/types/src/stories/Automerge.stories.d.ts +25 -24
  34. package/dist/types/src/stories/Automerge.stories.d.ts.map +1 -1
  35. package/dist/types/src/stories/Comments.stories.d.ts +1 -1
  36. package/dist/types/src/stories/Comments.stories.d.ts.map +1 -1
  37. package/dist/types/src/stories/EditorToolbar.stories.d.ts +26 -26
  38. package/dist/types/src/stories/EditorToolbar.stories.d.ts.map +1 -1
  39. package/dist/types/src/stories/Experimental.stories.d.ts +1 -1
  40. package/dist/types/src/stories/Markdown.stories.d.ts +1 -1
  41. package/dist/types/src/stories/Outliner.stories.d.ts +2 -2
  42. package/dist/types/src/stories/Outliner.stories.d.ts.map +1 -1
  43. package/dist/types/src/stories/Popover.stories.d.ts +2 -2
  44. package/dist/types/src/stories/Popover.stories.d.ts.map +1 -1
  45. package/dist/types/src/stories/Preview.stories.d.ts +1 -1
  46. package/dist/types/src/stories/Preview.stories.d.ts.map +1 -1
  47. package/dist/types/src/stories/TextEditor.stories.d.ts +1 -1
  48. package/dist/types/src/stories/components/EditorStory.d.ts +3 -3
  49. package/dist/types/src/stories/components/EditorStory.d.ts.map +1 -1
  50. package/dist/types/src/stories/components/util.d.ts +3 -3
  51. package/dist/types/src/stories/components/util.d.ts.map +1 -1
  52. package/dist/types/src/translations.d.ts +24 -24
  53. package/dist/types/src/translations.d.ts.map +1 -1
  54. package/dist/types/src/util/react.d.ts +1 -4
  55. package/dist/types/src/util/react.d.ts.map +1 -1
  56. package/dist/types/tsconfig.tsbuildinfo +1 -1
  57. package/package.json +45 -45
  58. package/src/components/Editor/Editor.stories.tsx +6 -7
  59. package/src/components/Editor/Editor.tsx +21 -27
  60. package/src/components/EditorContent/EditorContent.tsx +1 -2
  61. package/src/components/EditorMenuProvider/EditorMenuProvider.tsx +21 -28
  62. package/src/components/EditorMenuProvider/menu-presets.ts +1 -0
  63. package/src/components/EditorMenuProvider/useEditorMenu.ts +8 -1
  64. package/src/components/EditorPreviewProvider/EditorPreviewProvider.tsx +5 -7
  65. package/src/components/EditorToolbar/EditorToolbar.tsx +24 -61
  66. package/src/components/EditorToolbar/blocks.ts +53 -46
  67. package/src/components/EditorToolbar/formatting.ts +44 -46
  68. package/src/components/EditorToolbar/headings.ts +42 -49
  69. package/src/components/EditorToolbar/image.ts +16 -21
  70. package/src/components/EditorToolbar/index.ts +0 -1
  71. package/src/components/EditorToolbar/lists.ts +57 -0
  72. package/src/components/EditorToolbar/search.ts +16 -21
  73. package/src/components/EditorToolbar/view-mode.ts +34 -41
  74. package/src/stories/Automerge.stories.tsx +10 -12
  75. package/src/stories/Comments.stories.tsx +4 -5
  76. package/src/stories/EditorToolbar.stories.tsx +32 -17
  77. package/src/stories/Experimental.stories.tsx +6 -6
  78. package/src/stories/Markdown.stories.tsx +2 -2
  79. package/src/stories/Outliner.stories.tsx +4 -5
  80. package/src/stories/Popover.stories.tsx +9 -10
  81. package/src/stories/Preview.stories.tsx +60 -51
  82. package/src/stories/Tags.stories.tsx +5 -5
  83. package/src/stories/TextEditor.stories.tsx +2 -2
  84. package/src/stories/Theme.stories.tsx +2 -2
  85. package/src/stories/components/EditorStory.tsx +17 -12
  86. package/src/stories/components/util.tsx +49 -50
  87. package/src/translations.ts +29 -24
  88. package/src/util/react.tsx +2 -11
  89. package/dist/types/src/components/EditorToolbar/actions.d.ts +0 -24
  90. package/dist/types/src/components/EditorToolbar/actions.d.ts.map +0 -1
  91. package/dist/types/src/stories/CommandDialog.stories.d.ts +0 -14
  92. package/dist/types/src/stories/CommandDialog.stories.d.ts.map +0 -1
  93. package/src/components/EditorToolbar/actions.ts +0 -87
  94. package/src/stories/CommandDialog.stories.tsx +0 -81
@@ -6,30 +6,30 @@ var translations = [
6
6
  {
7
7
  "en-US": {
8
8
  [translationKey]: {
9
- "strong label": "Bold",
10
- "emphasis label": "Italics",
11
- "strikethrough label": "Strikethrough",
12
- "code label": "Code",
13
- "link label": "Link",
14
- "list-bullet label": "Bullet list",
15
- "list-ordered label": "Numbered list",
16
- "list-task label": "Task list",
17
- "blockquote label": "Block quote",
18
- "codeblock label": "Code block",
19
- "comment label": "Create comment",
20
- "selection overlaps existing comment label": "Selection overlaps existing comment",
21
- "select text to comment label": "Select text to comment",
22
- "image label": "Insert image",
23
- "table label": "Create table",
24
- "heading label": "Heading level",
25
- "heading level label_zero": "Paragraph",
26
- "heading level label_one": "Heading level {{count}}",
27
- "heading level label_other": "Heading level {{count}}",
28
- "search label": "Search",
29
- "view mode label": "Editor view",
30
- "preview mode label": "Markdown",
31
- "readonly mode label": "Read only",
32
- "source mode label": "Plain text"
9
+ "comment.label": "Create comment",
10
+ "image.label": "Insert image",
11
+ "search.label": "Search",
12
+ "block.label": "Block",
13
+ "block.blockquote.label": "Block quote",
14
+ "block.codeblock.label": "Code block",
15
+ "block.table.label": "Create table",
16
+ "formatting.label": "Formatting",
17
+ "formatting.strong.label": "Bold",
18
+ "formatting.emphasis.label": "Italics",
19
+ "formatting.strikethrough.label": "Strikethrough",
20
+ "formatting.code.label": "Code",
21
+ "formatting.link.label": "Link",
22
+ "list.bullet.label": "Bullet list",
23
+ "list.ordered.label": "Numbered list",
24
+ "list.task.label": "Task list",
25
+ "heading.label": "Heading level",
26
+ "heading-level.label_zero": "Paragraph",
27
+ "heading-level.label_one": "Heading level {{count}}",
28
+ "heading-level.label_other": "Heading level {{count}}",
29
+ "view-mode.label": "Editor view",
30
+ "view-mode.preview.label": "Markdown",
31
+ "view-mode.source.label": "Plain text",
32
+ "view-mode.readonly.label": "Read only"
33
33
  }
34
34
  }
35
35
  }
@@ -298,7 +298,7 @@ var EditorContent = /* @__PURE__ */ forwardRef(({ classNames, id, extensions, se
298
298
  ]);
299
299
  return /* @__PURE__ */ React.createElement("div", {
300
300
  role: "none",
301
- className: mx("is-full outline-none focus:border-accentSurface focus-within:border-neutralFocusIndicator", classNames),
301
+ className: mx("w-full outline-hidden focus:border-accent-surface focus-within:border-neutral-focus-indicator", classNames),
302
302
  ref: parentRef,
303
303
  ...focusable ? focusAttributes : {}
304
304
  });
@@ -704,7 +704,7 @@ import { useControllableState } from "@radix-ui/react-use-controllable-state";
704
704
  import React2, { Fragment, useCallback as useCallback2, useEffect as useEffect3, useRef as useRef2, useState as useState2 } from "react";
705
705
  import { addEventListener } from "@dxos/async";
706
706
  import { invariant } from "@dxos/invariant";
707
- import { DX_ANCHOR_ACTIVATE, Icon, Popover, toLocalizedString, useDynamicRef, useThemeContext, useTranslation } from "@dxos/react-ui";
707
+ import { DX_ANCHOR_ACTIVATE, Icon, Popover, ScrollArea, toLocalizedString, useDynamicRef, useThemeContext, useTranslation } from "@dxos/react-ui";
708
708
  var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-editor/src/components/EditorMenuProvider/EditorMenuProvider.tsx";
709
709
  var EditorMenuProvider = ({ children, view, groups, currentItem, open: openProp, defaultOpen, numItems = 8, onOpenChange, onActivate, onSelect, onCancel }) => {
710
710
  const { tx } = useThemeContext();
@@ -716,7 +716,7 @@ var EditorMenuProvider = ({ children, view, groups, currentItem, open: openProp,
716
716
  onChange: (open2) => {
717
717
  invariant(viewRef.current, void 0, {
718
718
  F: __dxlog_file2,
719
- L: 65,
719
+ L: 64,
720
720
  S: void 0,
721
721
  A: [
722
722
  "viewRef.current",
@@ -735,8 +735,8 @@ var EditorMenuProvider = ({ children, view, groups, currentItem, open: openProp,
735
735
  return;
736
736
  }
737
737
  return addEventListener(root, DX_ANCHOR_ACTIVATE, (event) => {
738
- const { trigger, refId } = event;
739
- if (!refId) {
738
+ const { trigger, dxn } = event;
739
+ if (!dxn) {
740
740
  triggerRef.current = trigger;
741
741
  if (onActivate) {
742
742
  onActivate({
@@ -758,7 +758,7 @@ var EditorMenuProvider = ({ children, view, groups, currentItem, open: openProp,
758
758
  const handleSelect = useCallback2((item) => {
759
759
  invariant(viewRef.current, void 0, {
760
760
  F: __dxlog_file2,
761
- L: 102,
761
+ L: 99,
762
762
  S: void 0,
763
763
  A: [
764
764
  "viewRef.current",
@@ -782,34 +782,36 @@ var EditorMenuProvider = ({ children, view, groups, currentItem, open: openProp,
782
782
  virtualRef: triggerRef
783
783
  }), /* @__PURE__ */ React2.createElement(Popover.Portal, null, /* @__PURE__ */ React2.createElement(Popover.Content, {
784
784
  align: "start",
785
- classNames: tx("menu.content", "menu--exotic-unfocusable", {
786
- elevation: "positioned"
787
- }, [
788
- "overflow-y-auto",
785
+ classNames: [
786
+ "flex flex-col",
789
787
  !menuGroups.length && "hidden"
790
- ]),
788
+ ],
791
789
  style: {
792
790
  maxBlockSize: 36 * numItems + 10
793
791
  },
794
- /**
795
- * NOTE: We keep the focus in the editor, but Radix routes escape key.
796
- */
792
+ // NOTE: We keep the focus in the editor, but Radix routes escape key.
797
793
  onEscapeKeyDown: () => {
798
- onCancel?.({
799
- view
800
- });
794
+ const currentView = viewRef.current;
795
+ if (currentView) {
796
+ onCancel?.({
797
+ view: currentView
798
+ });
799
+ }
801
800
  },
802
801
  onOpenAutoFocus: (event) => event.preventDefault()
803
802
  }, /* @__PURE__ */ React2.createElement(Popover.Viewport, {
804
- classNames: tx("menu.viewport", "menu__viewport--exotic-unfocusable", {})
805
- }, /* @__PURE__ */ React2.createElement(Menu, {
803
+ asChild: true,
804
+ classNames: "dx-container"
805
+ }, /* @__PURE__ */ React2.createElement(ScrollArea.Root, {
806
+ thin: true
807
+ }, /* @__PURE__ */ React2.createElement(ScrollArea.Viewport, null, /* @__PURE__ */ React2.createElement(Menu, {
806
808
  groups: menuGroups,
807
809
  currentItem,
808
810
  onSelect: handleSelect
809
- })), /* @__PURE__ */ React2.createElement(Popover.Arrow, null))), /* @__PURE__ */ React2.createElement("div", {
810
- ref: setRoot,
811
+ })))), /* @__PURE__ */ React2.createElement(Popover.Arrow, null))), /* @__PURE__ */ React2.createElement("div", {
811
812
  role: "none",
812
- className: "contents"
813
+ className: "contents",
814
+ ref: setRoot
813
815
  }, children));
814
816
  };
815
817
  var Menu = ({ groups, currentItem, onSelect }) => {
@@ -821,14 +823,14 @@ var Menu = ({ groups, currentItem, onSelect }) => {
821
823
  currentItem,
822
824
  onSelect
823
825
  }), index < groups.length - 1 && /* @__PURE__ */ React2.createElement("div", {
824
- className: tx("menu.separator", "menu__item", {})
826
+ className: tx("menu.separator", {})
825
827
  }))));
826
828
  };
827
829
  var MenuGroup = ({ group, currentItem, onSelect }) => {
828
830
  const { tx } = useThemeContext();
829
831
  const { t } = useTranslation();
830
832
  return /* @__PURE__ */ React2.createElement(React2.Fragment, null, group.label && /* @__PURE__ */ React2.createElement("div", {
831
- className: tx("menu.groupLabel", "menu__group__label", {})
833
+ className: tx("menu.groupLabel", {})
832
834
  }, /* @__PURE__ */ React2.createElement("span", null, toLocalizedString(group.label, t))), group.items.map((item) => /* @__PURE__ */ React2.createElement(MenuItem, {
833
835
  key: item.id,
834
836
  item,
@@ -856,13 +858,12 @@ var MenuItem = ({ item, current, onSelect }) => {
856
858
  ]);
857
859
  return /* @__PURE__ */ React2.createElement("li", {
858
860
  ref: listRef,
859
- className: tx("menu.item", "menu__item--exotic-unfocusable", {}, [
860
- current && "bg-hoverSurface"
861
+ className: tx("menu.item", {}, [
862
+ current && "bg-hover-surface"
861
863
  ]),
862
864
  onClick: handleSelect
863
865
  }, item.icon && /* @__PURE__ */ React2.createElement(Icon, {
864
- icon: item.icon,
865
- size: 5
866
+ icon: item.icon
866
867
  }), /* @__PURE__ */ React2.createElement("span", {
867
868
  className: "grow truncate"
868
869
  }, toLocalizedString(item.label, t)));
@@ -885,7 +886,7 @@ var useEditorMenu = ({ trigger, triggerKey, placeholder: placeholder2, filter =
885
886
  trigger: trigger2,
886
887
  ...props
887
888
  }) ?? [];
888
- return filter ? filterMenuGroups(groups, (item) => text ? item.label.toLowerCase().startsWith(text.toLowerCase()) : true) : groups;
889
+ return filter && trigger2 !== "@" ? filterMenuGroups(groups, (item) => text ? item.label.toLowerCase().startsWith(text.toLowerCase()) : true) : groups;
889
890
  }, [
890
891
  getMenu,
891
892
  filter
@@ -893,7 +894,7 @@ var useEditorMenu = ({ trigger, triggerKey, placeholder: placeholder2, filter =
893
894
  const handleOpenChange = useCallback3(async ({ view, open: open2 }) => {
894
895
  invariant2(view, void 0, {
895
896
  F: __dxlog_file3,
896
- L: 76,
897
+ L: 77,
897
898
  S: void 0,
898
899
  A: [
899
900
  "view",
@@ -936,10 +937,21 @@ var useEditorMenu = ({ trigger, triggerKey, placeholder: placeholder2, filter =
936
937
  handleOpenChange
937
938
  ]);
938
939
  const handleSelect = useCallback3(({ view, item }) => {
940
+ const { range } = view.state.field(popoverStateField) ?? {};
941
+ if (range) {
942
+ view.dispatch({
943
+ changes: {
944
+ from: range.from,
945
+ to: range.to,
946
+ insert: ""
947
+ }
948
+ });
949
+ }
939
950
  void item.onSelect?.({
940
951
  view,
941
952
  head: view.state.selection.main.head
942
953
  });
954
+ view.focus();
943
955
  }, []);
944
956
  const handleCancel = useCallback3(({ view }) => {
945
957
  const { range, trigger: trigger2 } = view.state.field(popoverStateField) ?? {};
@@ -1021,144 +1033,62 @@ var useEditorMenu = ({ trigger, triggerKey, placeholder: placeholder2, filter =
1021
1033
  import { Atom } from "@effect-atom/atom-react";
1022
1034
  import React3, { memo, useMemo as useMemo3 } from "react";
1023
1035
  import { ElevationProvider } from "@dxos/react-ui";
1024
- import { MenuProvider, ToolbarMenu, createGapSeparator, useMenuActions } from "@dxos/react-ui-menu";
1025
-
1026
- // src/components/EditorToolbar/actions.ts
1027
- import { createMenuAction, createMenuItemGroup } from "@dxos/react-ui-menu";
1028
- import { List, addList, removeList } from "@dxos/ui-editor";
1029
- var listStyles = {
1030
- bullet: "ph--list-bullets--regular",
1031
- ordered: "ph--list-numbers--regular",
1032
- task: "ph--list-checks--regular"
1033
- };
1034
- var createLists = (state, getView) => {
1035
- const value = state.listStyle ?? "";
1036
- const listGroupAction = createListGroupAction(value);
1037
- const listActionsMap = createListActions(value, getView);
1038
- return {
1039
- nodes: [
1040
- listGroupAction,
1041
- ...listActionsMap
1042
- ],
1043
- edges: [
1044
- {
1045
- source: "root",
1046
- target: "list"
1047
- },
1048
- ...listActionsMap.map(({ id }) => ({
1049
- source: listGroupAction.id,
1050
- target: id
1051
- }))
1052
- ]
1053
- };
1054
- };
1055
- var createEditorAction = (id, props, invoke) => {
1056
- const { label = [
1057
- `${id} label`,
1058
- {
1059
- ns: translationKey
1060
- }
1061
- ], ...rest } = props;
1062
- return createMenuAction(id, invoke, {
1063
- label,
1064
- ...rest
1065
- });
1066
- };
1067
- var createEditorActionGroup = (id, props, icon) => {
1068
- const { label = [
1069
- `${id} label`,
1070
- {
1071
- ns: translationKey
1072
- }
1073
- ], ...rest } = props;
1074
- return createMenuItemGroup(id, {
1075
- label,
1076
- icon,
1077
- iconOnly: true,
1078
- ...rest
1079
- });
1080
- };
1081
- var createListGroupAction = (value) => createEditorActionGroup("list", {
1082
- variant: "toggleGroup",
1083
- selectCardinality: "single",
1084
- value
1085
- });
1086
- var createListActions = (value, getView) => Object.entries(listStyles).map(([listStyle, icon]) => {
1087
- const checked = value === listStyle;
1088
- return createEditorAction(`list-${listStyle}`, {
1089
- checked,
1090
- icon
1091
- }, () => {
1092
- const view = getView();
1093
- if (!view) {
1094
- return;
1095
- }
1096
- const listType = listStyle === "ordered" ? List.Ordered : listStyle === "bullet" ? List.Bullet : List.Task;
1097
- if (checked) {
1098
- removeList(listType)(view);
1099
- } else {
1100
- addList(listType)(view);
1101
- }
1102
- });
1103
- });
1036
+ import { Menu as Menu2, MenuBuilder, useMenuActions } from "@dxos/react-ui-menu";
1104
1037
 
1105
1038
  // src/components/EditorToolbar/blocks.ts
1106
1039
  import { addBlockquote, addCodeblock, insertTable, removeBlockquote, removeCodeblock } from "@dxos/ui-editor";
1107
- var createBlockGroupAction = (value) => createEditorActionGroup("block", {
1108
- variant: "toggleGroup",
1109
- selectCardinality: "single",
1110
- value
1111
- });
1112
- var createBlockActions = (value, getView, blankLine) => Object.entries({
1040
+ var blockTypes = {
1113
1041
  blockquote: "ph--quotes--regular",
1114
1042
  codeblock: "ph--code-block--regular",
1115
1043
  table: "ph--table--regular"
1116
- }).map(([type, icon]) => {
1117
- const checked = type === value;
1118
- return createEditorAction(type, {
1119
- checked,
1120
- ...type === "table" && {
1121
- disabled: !!blankLine
1122
- },
1123
- icon
1124
- }, () => {
1125
- const view = getView();
1126
- if (!view) {
1127
- return;
1128
- }
1129
- switch (type) {
1130
- case "blockquote":
1131
- checked ? removeBlockquote(view) : addBlockquote(view);
1132
- break;
1133
- case "codeblock":
1134
- checked ? removeCodeblock(view) : addCodeblock(view);
1135
- break;
1136
- case "table":
1137
- insertTable(view);
1138
- break;
1139
- }
1140
- });
1141
- });
1142
- var createBlocks = (state, getView) => {
1044
+ };
1045
+ var addBlocks = (state, getView) => (builder) => {
1143
1046
  const value = state?.blockQuote ? "blockquote" : state.blockType ?? "";
1144
- const blockGroupAction = createBlockGroupAction(value);
1145
- const blockActions = createBlockActions(value, getView, state.blankLine);
1146
- return {
1147
- nodes: [
1148
- blockGroupAction,
1149
- ...blockActions
1150
- ],
1151
- edges: [
1047
+ builder.group("block", {
1048
+ label: [
1049
+ "block.label",
1152
1050
  {
1153
- source: "root",
1154
- target: "block"
1155
- },
1156
- ...blockActions.map(({ id }) => ({
1157
- source: blockGroupAction.id,
1158
- target: id
1159
- }))
1160
- ]
1161
- };
1051
+ ns: translationKey
1052
+ }
1053
+ ],
1054
+ iconOnly: true,
1055
+ variant: "toggleGroup",
1056
+ selectCardinality: "single",
1057
+ value
1058
+ }, (group) => {
1059
+ for (const [type, icon] of Object.entries(blockTypes)) {
1060
+ const checked = type === value;
1061
+ group.action(type, {
1062
+ label: [
1063
+ `block.${type}.label`,
1064
+ {
1065
+ ns: translationKey
1066
+ }
1067
+ ],
1068
+ checked,
1069
+ ...type === "table" && {
1070
+ disabled: !!state.blankLine
1071
+ },
1072
+ icon
1073
+ }, () => {
1074
+ const view = getView();
1075
+ if (!view) {
1076
+ return;
1077
+ }
1078
+ switch (type) {
1079
+ case "blockquote":
1080
+ checked ? removeBlockquote(view) : addBlockquote(view);
1081
+ break;
1082
+ case "codeblock":
1083
+ checked ? removeCodeblock(view) : addCodeblock(view);
1084
+ break;
1085
+ case "table":
1086
+ insertTable(view);
1087
+ break;
1088
+ }
1089
+ });
1090
+ }
1091
+ });
1162
1092
  };
1163
1093
 
1164
1094
  // src/components/EditorToolbar/formatting.ts
@@ -1170,201 +1100,222 @@ var formats = {
1170
1100
  code: "ph--code--regular",
1171
1101
  link: "ph--link--regular"
1172
1102
  };
1173
- var createFormattingGroup = (formatting) => createEditorActionGroup("formatting", {
1174
- variant: "toggleGroup",
1175
- selectCardinality: "multiple",
1176
- value: Object.keys(formats).filter((key) => !!formatting[key])
1177
- });
1178
- var createFormattingActions = (formatting, getView) => Object.entries(formats).map(([type, icon]) => {
1179
- const checked = !!formatting[type];
1180
- return createEditorAction(type, {
1181
- checked,
1182
- icon
1183
- }, () => {
1184
- const view = getView();
1185
- if (!view) {
1186
- return;
1187
- }
1188
- if (type === "link") {
1189
- checked ? removeLink(view) : addLink()(view);
1190
- return;
1103
+ var addFormatting = (state, getView) => (builder) => {
1104
+ const formatting = state;
1105
+ builder.group("formatting", {
1106
+ label: [
1107
+ "formatting.label",
1108
+ {
1109
+ ns: translationKey
1110
+ }
1111
+ ],
1112
+ iconOnly: true,
1113
+ variant: "toggleGroup",
1114
+ selectCardinality: "multiple",
1115
+ value: Object.keys(formats).filter((key) => !!formatting[key])
1116
+ }, (group) => {
1117
+ for (const [type, icon] of Object.entries(formats)) {
1118
+ const checked = !!formatting[type];
1119
+ group.action(type, {
1120
+ label: [
1121
+ `formatting.${type}.label`,
1122
+ {
1123
+ ns: translationKey
1124
+ }
1125
+ ],
1126
+ checked,
1127
+ icon
1128
+ }, () => {
1129
+ const view = getView();
1130
+ if (!view) {
1131
+ return;
1132
+ }
1133
+ if (type === "link") {
1134
+ checked ? removeLink(view) : addLink()(view);
1135
+ return;
1136
+ }
1137
+ setStyle(type === "strong" ? Inline.Strong : type === "emphasis" ? Inline.Emphasis : type === "strikethrough" ? Inline.Strikethrough : Inline.Code, !checked)(view);
1138
+ });
1191
1139
  }
1192
- const inlineType = type === "strong" ? Inline.Strong : type === "emphasis" ? Inline.Emphasis : type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
1193
- setStyle(inlineType, !checked)(view);
1194
1140
  });
1195
- });
1196
- var createFormatting = (state, getView) => {
1197
- const formattingGroupAction = createFormattingGroup(state);
1198
- const formattingActions = createFormattingActions(state, getView);
1199
- return {
1200
- nodes: [
1201
- formattingGroupAction,
1202
- ...formattingActions
1203
- ],
1204
- edges: [
1205
- {
1206
- source: "root",
1207
- target: "formatting"
1208
- },
1209
- ...formattingActions.map(({ id }) => ({
1210
- source: formattingGroupAction.id,
1211
- target: id
1212
- }))
1213
- ]
1214
- };
1215
1141
  };
1216
1142
 
1217
1143
  // src/components/EditorToolbar/headings.ts
1218
1144
  import { setHeading } from "@dxos/ui-editor";
1219
- var createHeadingGroupAction = (value) => createEditorActionGroup("heading", {
1220
- variant: "dropdownMenu",
1221
- applyActive: true,
1222
- selectCardinality: "single",
1223
- // TODO(wittjosiah): Remove? Not sure this does anything.
1224
- value
1225
- }, "ph--text-h--regular");
1226
- var createHeadingActions = (currentLevel, getView) => Object.entries({
1227
- "0": "ph--paragraph--regular",
1228
- "1": "ph--text-h-one--regular",
1229
- "2": "ph--text-h-two--regular",
1230
- "3": "ph--text-h-three--regular",
1231
- "4": "ph--text-h-four--regular",
1232
- "5": "ph--text-h-five--regular",
1233
- "6": "ph--text-h-six--regular"
1234
- }).map(([levelStr, icon]) => {
1235
- const level = parseInt(levelStr);
1236
- return createEditorAction(`heading--${levelStr}`, {
1237
- label: [
1238
- "heading level label",
1239
- {
1240
- count: level,
1241
- ns: translationKey
1242
- }
1243
- ],
1244
- icon,
1245
- checked: levelStr === currentLevel
1246
- }, () => setHeading(level)(getView()));
1247
- });
1145
+ var headingIcons = {
1146
+ 0: "ph--paragraph--regular",
1147
+ 1: "ph--text-h-one--regular",
1148
+ 2: "ph--text-h-two--regular",
1149
+ 3: "ph--text-h-three--regular",
1150
+ 4: "ph--text-h-four--regular",
1151
+ 5: "ph--text-h-five--regular",
1152
+ 6: "ph--text-h-six--regular"
1153
+ };
1248
1154
  var computeHeadingValue = (state) => {
1249
1155
  const blockType = state ? state.blockType : "paragraph";
1250
1156
  const heading = blockType && /heading(\d)/.exec(blockType);
1251
1157
  return heading ? heading[1] : blockType === "paragraph" || !blockType ? "0" : "";
1252
1158
  };
1253
- var createHeadings = (state, getView) => {
1159
+ var addHeadings = (state, getView) => (builder) => {
1254
1160
  const headingValue = computeHeadingValue(state);
1255
- const headingGroupAction = createHeadingGroupAction(headingValue);
1256
- const headingActions = createHeadingActions(headingValue, getView);
1257
- return {
1258
- nodes: [
1259
- headingGroupAction,
1260
- ...headingActions
1261
- ],
1262
- edges: [
1161
+ builder.group("heading", {
1162
+ label: [
1163
+ "heading.label",
1263
1164
  {
1264
- source: "root",
1265
- target: "heading"
1266
- },
1267
- ...headingActions.map(({ id }) => ({
1268
- source: headingGroupAction.id,
1269
- target: id
1270
- }))
1271
- ]
1272
- };
1165
+ ns: translationKey
1166
+ }
1167
+ ],
1168
+ icon: "ph--text-h--regular",
1169
+ iconOnly: true,
1170
+ variant: "dropdownMenu",
1171
+ applyActive: true,
1172
+ selectCardinality: "single",
1173
+ // TODO(wittjosiah): Remove? Not sure this does anything.
1174
+ value: headingValue
1175
+ }, (group) => {
1176
+ for (const [levelStr, icon] of Object.entries(headingIcons)) {
1177
+ const level = parseInt(levelStr);
1178
+ group.action(`heading--${levelStr}`, {
1179
+ label: [
1180
+ "heading-level.label",
1181
+ {
1182
+ count: level,
1183
+ ns: translationKey
1184
+ }
1185
+ ],
1186
+ icon,
1187
+ checked: levelStr === headingValue
1188
+ }, () => setHeading(level)(getView()));
1189
+ }
1190
+ });
1273
1191
  };
1274
1192
 
1275
1193
  // src/components/EditorToolbar/image.ts
1276
- var createImageUploadAction = (onImageUpload) => createEditorAction("image", {
1277
- testId: "editor.toolbar.image",
1278
- icon: "ph--image-square--regular"
1279
- }, onImageUpload);
1280
- var createImageUpload = (onImageUpload) => ({
1281
- nodes: [
1282
- createImageUploadAction(onImageUpload)
1283
- ],
1284
- edges: [
1285
- {
1286
- source: "root",
1287
- target: "image"
1194
+ var addImageUpload = (onImageUpload) => (builder) => {
1195
+ builder.action("image", {
1196
+ label: [
1197
+ "image.label",
1198
+ {
1199
+ ns: translationKey
1200
+ }
1201
+ ],
1202
+ testId: "editor.toolbar.image",
1203
+ icon: "ph--image-square--regular"
1204
+ }, onImageUpload);
1205
+ };
1206
+
1207
+ // src/components/EditorToolbar/lists.ts
1208
+ import { List, addList, removeList } from "@dxos/ui-editor";
1209
+ var listStyles = {
1210
+ bullet: "ph--list-bullets--regular",
1211
+ ordered: "ph--list-numbers--regular",
1212
+ task: "ph--list-checks--regular"
1213
+ };
1214
+ var addLists = (state, getView) => (builder) => {
1215
+ const value = state.listStyle ?? "";
1216
+ builder.group("list", {
1217
+ label: [
1218
+ "list.label",
1219
+ {
1220
+ ns: translationKey
1221
+ }
1222
+ ],
1223
+ iconOnly: true,
1224
+ variant: "toggleGroup",
1225
+ selectCardinality: "single",
1226
+ value
1227
+ }, (group) => {
1228
+ for (const [listStyle, icon] of Object.entries(listStyles)) {
1229
+ const checked = value === listStyle;
1230
+ group.action(`list-${listStyle}`, {
1231
+ label: [
1232
+ `list.${listStyle}.label`,
1233
+ {
1234
+ ns: translationKey
1235
+ }
1236
+ ],
1237
+ checked,
1238
+ icon
1239
+ }, () => {
1240
+ const view = getView();
1241
+ if (!view) {
1242
+ return;
1243
+ }
1244
+ const listType = listStyle === "ordered" ? List.Ordered : listStyle === "bullet" ? List.Bullet : List.Task;
1245
+ if (checked) {
1246
+ removeList(listType)(view);
1247
+ } else {
1248
+ addList(listType)(view);
1249
+ }
1250
+ });
1288
1251
  }
1289
- ]
1290
- });
1252
+ });
1253
+ };
1291
1254
 
1292
1255
  // src/components/EditorToolbar/search.ts
1293
1256
  import { openSearchPanel } from "@codemirror/search";
1294
- var createSearchAction = (getView) => createEditorAction("search", {
1295
- testId: "editor.toolbar.search",
1296
- icon: "ph--magnifying-glass--regular"
1297
- }, () => openSearchPanel(getView()));
1298
- var createSearch = (getView) => ({
1299
- nodes: [
1300
- createSearchAction(getView)
1301
- ],
1302
- edges: [
1303
- {
1304
- source: "root",
1305
- target: "search"
1306
- }
1307
- ]
1308
- });
1257
+ var addSearch = (getView) => (builder) => {
1258
+ builder.action("search", {
1259
+ label: [
1260
+ "search.label",
1261
+ {
1262
+ ns: translationKey
1263
+ }
1264
+ ],
1265
+ testId: "editor.toolbar.search",
1266
+ icon: "ph--magnifying-glass--regular"
1267
+ }, () => openSearchPanel(getView()));
1268
+ };
1309
1269
 
1310
1270
  // src/components/EditorToolbar/view-mode.ts
1311
- var createViewModeGroupAction = (value) => createEditorActionGroup("viewMode", {
1312
- variant: "dropdownMenu",
1313
- applyActive: true,
1314
- selectCardinality: "single",
1315
- value
1316
- }, "ph--eye--regular");
1317
- var createViewModeActions = (value, onViewModeChange) => Object.entries({
1271
+ var viewModes = {
1318
1272
  preview: "ph--eye--regular",
1319
1273
  source: "ph--pencil-simple--regular",
1320
1274
  readonly: "ph--pencil-slash--regular"
1321
- }).map(([viewMode, icon]) => {
1322
- const checked = viewMode === value;
1323
- return createEditorAction(`view-mode--${viewMode}`, {
1275
+ };
1276
+ var addViewMode = (state, onViewModeChange) => (builder) => {
1277
+ const value = state.viewMode ?? "source";
1278
+ builder.group("viewMode", {
1324
1279
  label: [
1325
- `${viewMode} mode label`,
1280
+ "view-mode.label",
1326
1281
  {
1327
1282
  ns: translationKey
1328
1283
  }
1329
1284
  ],
1330
- checked,
1331
- icon
1332
- }, () => onViewModeChange(viewMode));
1333
- });
1334
- var createViewMode = (state, onViewModeChange) => {
1335
- const value = state.viewMode ?? "source";
1336
- const viewModeGroupAction = createViewModeGroupAction(value);
1337
- const viewModeActions = createViewModeActions(value, onViewModeChange);
1338
- return {
1339
- nodes: [
1340
- viewModeGroupAction,
1341
- ...viewModeActions
1342
- ],
1343
- edges: [
1344
- {
1345
- source: "root",
1346
- target: "viewMode"
1347
- },
1348
- ...viewModeActions.map(({ id }) => ({
1349
- source: viewModeGroupAction.id,
1350
- target: id
1351
- }))
1352
- ]
1353
- };
1285
+ icon: "ph--eye--regular",
1286
+ iconOnly: true,
1287
+ variant: "dropdownMenu",
1288
+ applyActive: true,
1289
+ selectCardinality: "single",
1290
+ value
1291
+ }, (group) => {
1292
+ for (const [viewMode, icon] of Object.entries(viewModes)) {
1293
+ const checked = viewMode === value;
1294
+ group.action(`view-mode--${viewMode}`, {
1295
+ label: [
1296
+ `view-mode.${viewMode}.label`,
1297
+ {
1298
+ ns: translationKey
1299
+ }
1300
+ ],
1301
+ checked,
1302
+ icon
1303
+ }, () => onViewModeChange(viewMode));
1304
+ }
1305
+ });
1354
1306
  };
1355
1307
 
1356
1308
  // src/components/EditorToolbar/EditorToolbar.tsx
1357
1309
  var EditorToolbar = /* @__PURE__ */ memo(({ classNames, role, attendableId, onAction, ...props }) => {
1358
- const menuProps = useEditorToolbarActionGraph(props);
1310
+ const menuActions = useEditorToolbarActionGraph(props);
1359
1311
  return /* @__PURE__ */ React3.createElement(ElevationProvider, {
1360
1312
  elevation: role === "section" ? "positioned" : "base"
1361
- }, /* @__PURE__ */ React3.createElement(MenuProvider, {
1362
- ...menuProps,
1313
+ }, /* @__PURE__ */ React3.createElement(Menu2.Root, {
1314
+ ...menuActions,
1363
1315
  attendableId,
1364
1316
  onAction
1365
- }, /* @__PURE__ */ React3.createElement(ToolbarMenu, {
1366
- classNames,
1367
- textBlockWidth: true
1317
+ }, /* @__PURE__ */ React3.createElement(Menu2.Toolbar, {
1318
+ classNames
1368
1319
  })));
1369
1320
  });
1370
1321
  var useEditorToolbarActionGraph = ({ state, getView, customActions, ...features }) => {
@@ -1389,41 +1340,8 @@ var useEditorToolbarActionGraph = ({ state, getView, customActions, ...features
1389
1340
  };
1390
1341
  var createToolbarActions = ({ state, getView, customActions, ...features }) => {
1391
1342
  return Atom.make((get) => {
1392
- const graph = {
1393
- nodes: [],
1394
- edges: []
1395
- };
1396
- const addSubGraph = (graph2, subGraph) => {
1397
- graph2.nodes.push(...subGraph.nodes);
1398
- graph2.edges.push(...subGraph.edges);
1399
- };
1400
1343
  const stateSnapshot = get(state);
1401
- if (features?.showHeadings ?? true) {
1402
- addSubGraph(graph, createHeadings(stateSnapshot, getView));
1403
- }
1404
- if (features?.showFormatting ?? true) {
1405
- addSubGraph(graph, createFormatting(stateSnapshot, getView));
1406
- }
1407
- if (features?.showLists ?? true) {
1408
- addSubGraph(graph, createLists(stateSnapshot, getView));
1409
- }
1410
- if (features?.showBlocks ?? true) {
1411
- addSubGraph(graph, createBlocks(stateSnapshot, getView));
1412
- }
1413
- if (features?.onImageUpload) {
1414
- addSubGraph(graph, createImageUpload(features.onImageUpload));
1415
- }
1416
- addSubGraph(graph, createGapSeparator());
1417
- if (customActions) {
1418
- addSubGraph(graph, get(customActions));
1419
- }
1420
- if (features?.showSearch ?? true) {
1421
- addSubGraph(graph, createSearch(getView));
1422
- }
1423
- if (features?.onViewModeChange) {
1424
- addSubGraph(graph, createViewMode(stateSnapshot, features.onViewModeChange));
1425
- }
1426
- return graph;
1344
+ return MenuBuilder.make().subgraph(features?.showHeadings !== false && addHeadings(stateSnapshot, getView)).subgraph(features?.showFormatting !== false && addFormatting(stateSnapshot, getView)).subgraph(features?.showLists !== false && addLists(stateSnapshot, getView)).subgraph(features?.showBlocks !== false && addBlocks(stateSnapshot, getView)).subgraph(features?.onImageUpload && addImageUpload(features.onImageUpload)).separator("gap").subgraph(customActions && get(customActions)).subgraph(features?.showSearch !== false && addSearch(getView)).subgraph(features?.onViewModeChange && addViewMode(stateSnapshot, features.onViewModeChange)).build();
1427
1345
  });
1428
1346
  };
1429
1347
 
@@ -1465,15 +1383,17 @@ var EditorRoot = /* @__PURE__ */ forwardRef2(({ children, extensions: extensions
1465
1383
  }, children));
1466
1384
  });
1467
1385
  EditorRoot.displayName = "Editor.Root";
1386
+ var EDITOR_VIEWPORT_NAME = "Editor.Viewport";
1468
1387
  var EditorViewport = ({ classNames, children }) => {
1469
1388
  return /* @__PURE__ */ React4.createElement("div", {
1470
1389
  role: "none",
1471
- className: mx2("grid grid-rows-[min-content_1fr] bs-full overflow-hidden", classNames)
1390
+ className: mx2("grid grid-rows-[min-content_1fr] h-full overflow-hidden", classNames)
1472
1391
  }, children);
1473
1392
  };
1474
- EditorViewport.displayName = "Editor.Viewport";
1393
+ EditorViewport.displayName = EDITOR_VIEWPORT_NAME;
1394
+ var EDITOR_CONTENT_NAME = "Editor.Content";
1475
1395
  var EditorContent2 = ({ extensions: providedExtensions, ...props }) => {
1476
- const { extensions: additionalExtensions = [], setController } = useEditorContext(EditorContent2.displayName);
1396
+ const { extensions: additionalExtensions = [], setController } = useEditorContext(EDITOR_CONTENT_NAME);
1477
1397
  const extensions = useMemo5(() => [
1478
1398
  additionalExtensions,
1479
1399
  providedExtensions
@@ -1487,13 +1407,14 @@ var EditorContent2 = ({ extensions: providedExtensions, ...props }) => {
1487
1407
  ref: setController
1488
1408
  });
1489
1409
  };
1490
- EditorContent2.displayName = "Editor.Content";
1410
+ EditorContent2.displayName = EDITOR_CONTENT_NAME;
1411
+ var EDITOR_TOOLBAR_NAME = "Editor.Toolbar";
1491
1412
  var EditorToolbar2 = (props) => {
1492
- const { controller, state } = useEditorContext(EditorToolbar2.displayName);
1413
+ const { controller, state } = useEditorContext(EDITOR_TOOLBAR_NAME);
1493
1414
  const getView = useCallback4(() => {
1494
1415
  invariant3(controller?.view, void 0, {
1495
1416
  F: __dxlog_file4,
1496
- L: 140,
1417
+ L: 153,
1497
1418
  S: void 0,
1498
1419
  A: [
1499
1420
  "controller?.view",
@@ -1510,7 +1431,7 @@ var EditorToolbar2 = (props) => {
1510
1431
  state
1511
1432
  });
1512
1433
  };
1513
- EditorToolbar2.displayName = "Editor.Toolbar";
1434
+ EditorToolbar2.displayName = EDITOR_TOOLBAR_NAME;
1514
1435
  var Editor = {
1515
1436
  Root: EditorRoot,
1516
1437
  Viewport: EditorViewport,
@@ -1529,20 +1450,20 @@ var EditorPreviewProvider = ({ children, onLookup }) => {
1529
1450
  const [value, setValue] = useState5({});
1530
1451
  const [open, setOpen] = useState5(false);
1531
1452
  const handleActivate = useCallback5((event) => {
1532
- const { refId, label, trigger: dxTrigger } = event;
1453
+ const { dxn, label, trigger } = event;
1533
1454
  setValue((value2) => ({
1534
1455
  ...value2,
1535
1456
  link: {
1536
1457
  label,
1537
- ref: refId
1458
+ dxn
1538
1459
  },
1539
1460
  pending: true
1540
1461
  }));
1541
- triggerRef.current = dxTrigger;
1462
+ triggerRef.current = trigger;
1542
1463
  queueMicrotask(() => setOpen(true));
1543
1464
  void onLookup?.({
1544
1465
  label,
1545
- ref: refId
1466
+ dxn
1546
1467
  }).then((target) => setValue((value2) => ({
1547
1468
  ...value2,
1548
1469
  target: target ?? void 0,
@@ -1574,9 +1495,9 @@ var EditorPreviewProvider = ({ children, onLookup }) => {
1574
1495
  }, /* @__PURE__ */ React5.createElement(Popover2.VirtualTrigger, {
1575
1496
  virtualRef: triggerRef
1576
1497
  }), /* @__PURE__ */ React5.createElement("div", {
1577
- ref: setRoot,
1578
1498
  role: "none",
1579
- className: "contents"
1499
+ className: "contents",
1500
+ ref: setRoot
1580
1501
  }, children)));
1581
1502
  };
1582
1503
  export {
@@ -1597,6 +1518,7 @@ export {
1597
1518
  popoverRangeEffect,
1598
1519
  popoverStateField,
1599
1520
  translations,
1521
+ useEditorContext,
1600
1522
  useEditorMenu,
1601
1523
  useEditorPreview,
1602
1524
  useEditorToolbar,