@stesura/react-wordgard 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +699 -237
  3. package/dist/ReactWordgard.js +2 -4
  4. package/dist/components/ChildNodeViews.js +2 -4
  5. package/dist/components/DecorationRoot.d.ts +6 -0
  6. package/dist/components/DecorationRoot.js +7 -4
  7. package/dist/components/ErrorBoundary.js +3 -5
  8. package/dist/components/SeparatorHackView.js +1 -2
  9. package/dist/components/ShapeView.js +2 -4
  10. package/dist/components/TextNodeView.js +2 -3
  11. package/dist/components/TrailingHackView.js +2 -3
  12. package/dist/components/WidgetView.js +2 -5
  13. package/dist/components/WordgardDoc.d.ts +5 -0
  14. package/dist/components/WordgardDoc.js +8 -6
  15. package/dist/components/WordgardEditor.d.ts +8 -0
  16. package/dist/components/WordgardEditor.js +10 -6
  17. package/dist/components/WordgardScope.d.ts +14 -0
  18. package/dist/components/WordgardScope.js +14 -0
  19. package/dist/components/WrapperView.js +1 -4
  20. package/dist/components/marks/MarkView.js +3 -6
  21. package/dist/components/marks/ReactMarkView.js +2 -4
  22. package/dist/components/nodes/DefaultNodeView.js +3 -7
  23. package/dist/components/nodes/DocNodeView.js +2 -3
  24. package/dist/composition.js +4 -6
  25. package/dist/contexts/DecorationContext.js +2 -5
  26. package/dist/contexts/DecorationRootContext.js +2 -4
  27. package/dist/contexts/EditorContext.d.ts +1 -0
  28. package/dist/contexts/EditorContext.js +3 -3
  29. package/dist/contexts/RenderStoreContext.js +3 -5
  30. package/dist/contexts/editorEvents.js +3 -6
  31. package/dist/decorations/ReactMarkType.d.ts +11 -0
  32. package/dist/decorations/ReactMarkType.js +6 -7
  33. package/dist/decorations/ReactShapeType.d.ts +16 -0
  34. package/dist/decorations/ReactShapeType.js +9 -11
  35. package/dist/decorations/ReactWidgetType.d.ts +10 -0
  36. package/dist/decorations/ReactWidgetType.js +6 -8
  37. package/dist/decorations/ReactWrapperType.d.ts +9 -0
  38. package/dist/decorations/ReactWrapperType.js +3 -6
  39. package/dist/decorations/iterDeco.js +3 -6
  40. package/dist/hooks/useEditorEffect.d.ts +7 -0
  41. package/dist/hooks/useEditorEffect.js +11 -7
  42. package/dist/hooks/useEditorEventCallback.d.ts +6 -0
  43. package/dist/hooks/useEditorEventCallback.js +7 -3
  44. package/dist/hooks/useEditorEventListener.d.ts +7 -0
  45. package/dist/hooks/useEditorEventListener.js +11 -11
  46. package/dist/hooks/useEditorLayoutEffect.d.ts +9 -0
  47. package/dist/hooks/useEditorLayoutEffect.js +13 -17
  48. package/dist/hooks/useEditorState.d.ts +5 -0
  49. package/dist/hooks/useEditorState.js +6 -4
  50. package/dist/hooks/useEditorStateSelector.d.ts +5 -0
  51. package/dist/hooks/useEditorStateSelector.js +5 -0
  52. package/dist/hooks/useIgnoreMutation.d.ts +5 -1
  53. package/dist/hooks/useIgnoreMutation.js +11 -10
  54. package/dist/hooks/useIsNodeSelected.d.ts +1 -0
  55. package/dist/hooks/useIsNodeSelected.js +3 -4
  56. package/dist/hooks/useMergedDOMRefs.d.ts +4 -0
  57. package/dist/hooks/useMergedDOMRefs.js +5 -4
  58. package/dist/hooks/useNodePos.d.ts +3 -0
  59. package/dist/hooks/useNodePos.js +5 -6
  60. package/dist/hooks/useSelectNode.d.ts +4 -0
  61. package/dist/hooks/useSelectNode.js +5 -4
  62. package/dist/hooks/useStopEvent.d.ts +6 -0
  63. package/dist/hooks/useStopEvent.js +8 -7
  64. package/dist/hooks/useWordgard.d.ts +1 -0
  65. package/dist/hooks/useWordgard.js +1 -2
  66. package/dist/index.d.ts +1 -0
  67. package/dist/index.js +2 -0
  68. package/dist/tile.js +3 -8
  69. package/dist/viewRoots.js +2 -3
  70. package/dist/wordgardInternals.js +2 -5
  71. package/package.json +1 -1
  72. package/skills/react-wordgard/SKILL.md +138 -10
@@ -1,7 +1,5 @@
1
- // Adapted from react-prosemirror's ReactEditorView, to fit Wordgard: it
2
- // extends Wordgard instead of EditorView and, where ReactEditorView replaces
3
- // the docView ProseMirror's constructor builds, has the base constructor build
4
- // a tile tree React renders.
1
+ // Adapted from react-prosemirror's ReactEditorView, to fit Wordgard: it extends Wordgard, and its
2
+ // base constructor builds a tile tree React renders, where ReactEditorView replaces the docView.
5
3
  import { Wordgard } from "wordgard/editor";
6
4
  import { GardState } from "wordgard/state";
7
5
  import { editorOf } from "./contexts/EditorContext.js";
@@ -1,7 +1,5 @@
1
- // Named after react-prosemirror's ChildNodeViews, rewritten for Wordgard: draws
2
- // what iterDeco lays out: nodes, text, mark wrappers, Wordgard's hack nodes and
3
- // React widgets. Native widgets aren't React's: ReactDocTile puts their DOM in
4
- // place after the commit.
1
+ // Named after react-prosemirror's ChildNodeViews, rewritten for Wordgard: draws what iterDeco lays
2
+ // out. Native widgets aren't React's: ReactDocTile puts their DOM in place after the commit.
5
3
  import React, { memo } from "react";
6
4
  import { cellOf } from "../contexts/RenderStoreContext.js";
7
5
  import { isReactWidget } from "../decorations/ReactWidgetType.js";
@@ -1,7 +1,13 @@
1
1
  import { type AllHTMLAttributes, type ReactNode } from "react";
2
+ /** `DecorationRoot`'s props: its root's attributes, and its children. */
2
3
  export type DecorationRootProps = AllHTMLAttributes<HTMLElement> & {
3
4
  children?: ReactNode;
4
5
  };
6
+ /**
7
+ * The root element of a React shape, wrapper, mark or widget: the tag the decoration says, with
8
+ * Wordgard's attributes merged with the props. See [React
9
+ * decorations](https://github.com/stesura/react-wordgard#react-decorations).
10
+ */
5
11
  export declare const DecorationRoot: import("react").ForwardRefExoticComponent<AllHTMLAttributes<HTMLElement> & {
6
12
  children?: ReactNode;
7
13
  } & import("react").RefAttributes<Element>>;
@@ -1,11 +1,14 @@
1
- // A React shape's, wrapper's or mark's root, drawn for its component: the tag
2
- // its Elt says, Wordgard's attributes and the root's ref, so the component
3
- // can't get them wrong. The component's own props win, but `className` joins
4
- // Wordgard's and `style` merges, its keys winning. Not in react-prosemirror.
1
+ // Not in react-prosemirror. The component's own props win, but `className` joins Wordgard's and
2
+ // `style` merges, its keys winning.
5
3
  import { createElement, forwardRef, useContext, useMemo, } from "react";
6
4
  import { DecorationRootContext } from "../contexts/DecorationRootContext.js";
7
5
  import { cssToStyle, htmlAttrsToReactProps } from "../helpers/props.js";
8
6
  import { mergeRefs, toCallbackRef } from "../helpers/refs.js";
7
+ /**
8
+ * The root element of a React shape, wrapper, mark or widget: the tag the decoration says, with
9
+ * Wordgard's attributes merged with the props. See [React
10
+ * decorations](https://github.com/stesura/react-wordgard#react-decorations).
11
+ */
9
12
  export const DecorationRoot = forwardRef(({ className, style, ...props }, ref) => {
10
13
  const root = useContext(DecorationRootContext);
11
14
  const rootRef = root?.ref;
@@ -1,8 +1,6 @@
1
- // Not in react-prosemirror: catches an error thrown while React renders the
2
- // document, for ReactDocTile to throw it from the update. React 18 rethrows it
3
- // from flushSync, React 19 reports it as uncaught and commits nothing, and the
4
- // tiles can't be built over what didn't commit. A class: React has no hook for
5
- // this.
1
+ // Not in react-prosemirror: catches a render error for ReactDocTile to throw from the update. React
2
+ // 18 rethrows it from flushSync, React 19 reports it and commits nothing. A class: React has no
3
+ // hook for this.
6
4
  import { Component } from "react";
7
5
  export class ErrorBoundary extends Component {
8
6
  state = { failed: false };
@@ -1,5 +1,4 @@
1
1
  // Named after react-prosemirror's SeparatorHackView, rewritten for Wordgard: the
2
- // `<img class="wg-buffer">` Wordgard puts at the start and end of an inline plot
3
- // (`Widget.img`), which gives the cursor somewhere to go.
2
+ // `<img class="wg-buffer">` (`Widget.img`) at the ends of an inline plot.
4
3
  import React from "react";
5
4
  export const SeparatorHackView = () => React.createElement("img", { className: "wg-buffer" });
@@ -1,7 +1,5 @@
1
- // Named after react-prosemirror's ReactNodeView, for Wordgard: draws a React
2
- // shape's component, with the node's content as its children. ReactDocTile
3
- // builds the tiles over what it commits; the component's own commits are
4
- // sorted out of Wordgard's DOM observer (`sortRecords`).
1
+ // Named after react-prosemirror's ReactNodeView, for Wordgard: draws a React shape's component. Its
2
+ // own commits are sorted out of Wordgard's DOM observer (`sortRecords`).
5
3
  import React, { useMemo, useState } from "react";
6
4
  import { DecorationContext, createDecorationHandlers, decorationRoot, } from "../contexts/DecorationContext.js";
7
5
  import { atomRef, createShapeHandle, drawShape, nodePos, shapeAttributes, } from "../decorations/ReactShapeType.js";
@@ -1,5 +1,4 @@
1
- // Named after react-prosemirror's TextNodeView, rewritten for Wordgard: a text
2
- // leaf renders as a bare text node, its tile is built after the commit
3
- // (ReactDocTile). Skipped while its text is the same.
1
+ // Named after react-prosemirror's TextNodeView, rewritten for Wordgard: a bare text node, whose
2
+ // tile ReactDocTile builds after the commit.
4
3
  import { memo } from "react";
5
4
  export const TextNodeView = memo(({ text }) => text);
@@ -1,5 +1,4 @@
1
- // Named after react-prosemirror's TrailingHackView, rewritten for Wordgard: the
2
- // `<br>` Wordgard's own renderer adds to a textblock that needs one
3
- // (`Widget.br`).
1
+ // Named after react-prosemirror's TrailingHackView, rewritten for Wordgard: the `<br>` a textblock
2
+ // may need (`Widget.br`).
4
3
  import React from "react";
5
4
  export const TrailingHackView = () => React.createElement("br", null);
@@ -1,8 +1,5 @@
1
- // Named after react-prosemirror's WidgetView, rewritten for Wordgard: draws a
2
- // React widget's component, whose root element becomes the widget's DOM.
3
- // ReactDocTile builds its tile after the commit, so there's no view
4
- // description to register here. Skipped while the widget is `eq`, so the
5
- // component keeps its DOM, as Wordgard keeps an equal widget's.
1
+ // Named after react-prosemirror's WidgetView, rewritten for Wordgard. Skipped while the widget is
2
+ // `eq`, so the component keeps its DOM, as Wordgard keeps an equal widget's.
6
3
  import React, { memo, useMemo, useRef, useState } from "react";
7
4
  import { DecorationContext, createDecorationHandlers, decorationRoot, } from "../contexts/DecorationContext.js";
8
5
  import { DecorationRootContext } from "../contexts/DecorationRootContext.js";
@@ -1,4 +1,9 @@
1
1
  import React, { type HTMLAttributes } from "react";
2
2
  type Props = Omit<HTMLAttributes<HTMLDivElement>, "children">;
3
+ /**
4
+ * Puts the editor in the page, inside a `div` taking the props, and renders the document through a
5
+ * portal, in your React tree. It goes under its `<WordgardEditor>`, inside any other components,
6
+ * with other children before or after it. One per editor: a second throws.
7
+ */
3
8
  export declare const WordgardDoc: (props: Props) => React.JSX.Element;
4
9
  export {};
@@ -1,9 +1,6 @@
1
- // Named after react-prosemirror's ProseMirrorDoc, rewritten for Wordgard:
2
- // puts the editor's element in the page, inside a `div` taking the props, and
3
- // renders its document through a portal into Wordgard's content element, so
4
- // the document shares the app's React tree and contexts. The portal commits
5
- // first and builds the tiles; attaching the element then connects the editor,
6
- // as Wordgard's own editor is built before it's connected.
1
+ // Named after react-prosemirror's ProseMirrorDoc, rewritten for Wordgard. The portal commits first
2
+ // and builds the tiles; attaching the element then connects the editor, as Wordgard's own editor is
3
+ // built before it's connected.
7
4
  import React, { useCallback, useInsertionEffect, useLayoutEffect, useSyncExternalStore, } from "react";
8
5
  import { createPortal } from "react-dom";
9
6
  import { editorOf, useEditorContext } from "../contexts/EditorContext.js";
@@ -19,6 +16,11 @@ const DocPortal = ({ wg }) => {
19
16
  useLayoutEffect(() => portal.mount(), [portal]);
20
17
  return createPortal(element, wg.contentDOM);
21
18
  };
19
+ /**
20
+ * Puts the editor in the page, inside a `div` taking the props, and renders the document through a
21
+ * portal, in your React tree. It goes under its `<WordgardEditor>`, inside any other components,
22
+ * with other children before or after it. One per editor: a second throws.
23
+ */
22
24
  export const WordgardDoc = (props) => {
23
25
  const { wg } = useEditorContext();
24
26
  const attach = useCallback((dom) => {
@@ -3,5 +3,13 @@ import type { Wordgard } from "wordgard/editor";
3
3
  type Props = Omit<Wordgard.Spec, "parent"> & {
4
4
  children?: ReactNode;
5
5
  };
6
+ /**
7
+ * Creates a Wordgard editor from the spec (`doc`, `config`, `selection`, `state`, `scrollTo`) and
8
+ * provides it to its children. It draws no DOM of its own. The spec is read once, on mount: from
9
+ * then on the editor owns its state (see [Accessing the state outside the
10
+ * editor](https://github.com/stesura/react-wordgard#accessing-the-state-outside-the-editor)). In
11
+ * React's StrictMode (development only), it creates its editor twice and drops one, which is never
12
+ * put in the page.
13
+ */
6
14
  export declare const WordgardEditor: ({ children, ...spec }: Props) => React.JSX.Element;
7
15
  export {};
@@ -1,12 +1,16 @@
1
- // Named after react-prosemirror's ProseMirror component, rewritten for
2
- // Wordgard: creates the editor and provides it to what it holds, WordgardDoc
3
- // and the app's own components (menus, hooks). The spec is read once, as
4
- // react-prosemirror's `defaultState`: Wordgard's editor owns its state, so
5
- // changes go through `dispatch`, and configuration through Wordgard's
6
- // compartments or `GardState.appendConfig`.
1
+ // Named after react-prosemirror's ProseMirror component, rewritten for Wordgard. The spec is read
2
+ // once, as react-prosemirror's `defaultState`: Wordgard's editor owns its state.
7
3
  import React, { useState } from "react";
8
4
  import { ReactWordgard } from "../ReactWordgard.js";
9
5
  import { EditorContext, editorOf } from "../contexts/EditorContext.js";
6
+ /**
7
+ * Creates a Wordgard editor from the spec (`doc`, `config`, `selection`, `state`, `scrollTo`) and
8
+ * provides it to its children. It draws no DOM of its own. The spec is read once, on mount: from
9
+ * then on the editor owns its state (see [Accessing the state outside the
10
+ * editor](https://github.com/stesura/react-wordgard#accessing-the-state-outside-the-editor)). In
11
+ * React's StrictMode (development only), it creates its editor twice and drops one, which is never
12
+ * put in the page.
13
+ */
10
14
  export const WordgardEditor = ({ children, ...spec }) => {
11
15
  const [editor] = useState(() => editorOf(ReactWordgard.host(spec)));
12
16
  return React.createElement(EditorContext.Provider, { value: editor }, children);
@@ -0,0 +1,14 @@
1
+ import React, { type ReactNode } from "react";
2
+ import type { Wordgard } from "wordgard/editor";
3
+ type Props = {
4
+ wg: Wordgard;
5
+ children?: ReactNode;
6
+ };
7
+ /**
8
+ * Gives the components it holds `wg`, an editor a `WordgardEditor` made elsewhere, in place of the
9
+ * one around them: for a toolbar acting on whichever of a page's editors has focus. The hooks under
10
+ * it follow when `wg` changes: selectors subscribe to the new editor's state, callbacks and
11
+ * listeners get it, effects run again. Any other editor throws.
12
+ */
13
+ export declare const WordgardScope: ({ wg, children }: Props) => React.JSX.Element;
14
+ export {};
@@ -0,0 +1,14 @@
1
+ import React from "react";
2
+ import { EditorContext, findEditor } from "../contexts/EditorContext.js";
3
+ /**
4
+ * Gives the components it holds `wg`, an editor a `WordgardEditor` made elsewhere, in place of the
5
+ * one around them: for a toolbar acting on whichever of a page's editors has focus. The hooks under
6
+ * it follow when `wg` changes: selectors subscribe to the new editor's state, callbacks and
7
+ * listeners get it, effects run again. Any other editor throws.
8
+ */
9
+ export const WordgardScope = ({ wg, children }) => {
10
+ const editor = findEditor(wg);
11
+ if (!editor)
12
+ throw new Error("WordgardScope takes an editor a WordgardEditor made");
13
+ return React.createElement(EditorContext.Provider, { value: editor }, children);
14
+ };
@@ -1,7 +1,4 @@
1
- // Draws a React wrapper's component, with what it wraps (the node's shape, or
2
- // the element its `target` picks) as its children. Like ShapeView, it has no
3
- // effects: ReactDocTile builds the tiles over what it commits, and the
4
- // component's own commits are sorted out of Wordgard's DOM observer.
1
+ // Like ShapeView, no effects: ReactDocTile builds the tiles over what it commits.
5
2
  import React, { useMemo, useState } from "react";
6
3
  import { DecorationContext, createDecorationHandlers, decorationRoot, } from "../contexts/DecorationContext.js";
7
4
  import { createWrapperHandle, nodePos, shapeAttributes } from "../decorations/ReactShapeType.js";
@@ -1,9 +1,6 @@
1
- // Named after react-prosemirror's MarkView, rewritten for Wordgard: draws a
2
- // wrapper, either an element-shaped mark or the span holding a text run's
3
- // attribute-shaped marks, or a React mark's component. It draws what it holds
4
- // from its views, so it can be skipped while they keep their shape (iterDeco
5
- // keeps a wrapper's unchanged views; a node that changed gets its view from
6
- // its cell).
1
+ // Named after react-prosemirror's MarkView, rewritten for Wordgard: an element-shaped mark, the
2
+ // span of a text run's attribute-shaped marks, or a React mark. Memoised: iterDeco keeps a
3
+ // wrapper's unchanged views.
7
4
  import React, { createElement, memo } from "react";
8
5
  import { shapeOf } from "../../decorations/iterDeco.js";
9
6
  import { attrsToRecord, htmlAttrsToReactProps } from "../../helpers/index.js";
@@ -1,7 +1,5 @@
1
- // Named after react-prosemirror's ReactMarkView, rewritten for Wordgard: draws
2
- // a React mark's component around the marked content. As ShapeView, it has no
3
- // effects: ReactDocTile builds the tiles over what it commits, and the
4
- // component's own commits are sorted out of Wordgard's DOM observer.
1
+ // Named after react-prosemirror's ReactMarkView, rewritten for Wordgard. Like ShapeView, no
2
+ // effects: ReactDocTile builds the tiles over what it commits.
5
3
  import React, { useMemo, useState } from "react";
6
4
  import { DecorationContext, createDecorationHandlers, decorationRoot, } from "../../contexts/DecorationContext.js";
7
5
  import { drawMark } from "../../decorations/ReactMarkType.js";
@@ -1,10 +1,6 @@
1
- // Named after react-prosemirror's DefaultNodeView, rewritten for Wordgard: a
2
- // node renders as the shape Wordgard's decorations give it (its
3
- // buildNodeShape), with the plot's content in the hole. In Wordgard every node
4
- // type has a shape, so there's no missing `toDOM` to check for. Widgets, as a
5
- // node's shape or inside it, are drawn by their component when they're React
6
- // widgets, else draw nothing: ReactDocTile puts their DOM in place. React
7
- // shapes and wrappers in the shape are drawn by ShapeView and WrapperView.
1
+ // Named after react-prosemirror's DefaultNodeView, rewritten for Wordgard: a node renders as its
2
+ // decorated shape (buildNodeShape). Every Wordgard node type has a shape, so there's no missing
3
+ // `toDOM` to check for. Native widgets draw nothing: ReactDocTile puts their DOM in place.
8
4
  import React, { Component, createElement } from "react";
9
5
  import { Attributes, Elt } from "wordgard/doc";
10
6
  import { isReactShape, shapeAttributes } from "../../decorations/ReactShapeType.js";
@@ -1,6 +1,5 @@
1
- // Named after react-prosemirror's DocNodeView, rewritten for Wordgard: the
2
- // document's content renders straight into Wordgard's content element, which
3
- // is React's container.
1
+ // Named after react-prosemirror's DocNodeView, rewritten for Wordgard: renders straight into
2
+ // Wordgard's content element, React's container.
4
3
  import React from "react";
5
4
  import { ChildNodeViews } from "../ChildNodeViews.js";
6
5
  export const DocNodeView = ({ views }) => React.createElement(ChildNodeViews, { views: views });
@@ -1,9 +1,7 @@
1
- // How the React view keeps a composition alive through Wordgard's flush, as
2
- // Wordgard's ContentUpdate.composition does (src/editor/tile.ts in its repo):
3
- // the browser's text node stays as it is, in a tile of its own. React must not
4
- // write to it: when React drew it, React keeps rendering the value it last
5
- // committed there, in the wrappers it committed around it; when the browser
6
- // made it (or an element around it), React draws nothing in its place.
1
+ // Keeps a composition alive through Wordgard's flush, as Wordgard's ContentUpdate.composition does:
2
+ // the browser's text node stays, in a tile of its own, and React must not write to it. When React
3
+ // drew it, React keeps rendering what it last committed there; when the browser made it, React
4
+ // draws nothing in its place.
7
5
  import { Attributes, Elt } from "wordgard/doc";
8
6
  import { cursorWrappers, } from "./decorations/iterDeco.js";
9
7
  import { markOfTile, markTiles } from "./decorations/ReactMarkType.js";
@@ -1,8 +1,5 @@
1
- // The React decoration (shape, wrapper, mark or widget) a component is drawn
2
- // in, for the hooks react-prosemirror's node views use: its position, whether
3
- // its node is selected, and the handlers its components register. It takes
4
- // the place of react-prosemirror's GetPosContext, SelectNodeContext,
5
- // StopEventContext and IgnoreMutationContext.
1
+ // The React decoration a component is drawn in, for the decoration hooks. Replaces
2
+ // react-prosemirror's GetPosContext, SelectNodeContext, StopEventContext and IgnoreMutationContext.
6
3
  import { createContext, useContext } from "react";
7
4
  export const DecorationContext = createContext(null);
8
5
  export const useDecorationContext = (hook) => {
@@ -1,6 +1,4 @@
1
- // What DecorationRoot draws: the root a React shape's, wrapper's or mark's Elt
2
- // says, with Wordgard's attributes and the root's ref. Not in
3
- // react-prosemirror, whose node views draw their root themselves: Wordgard
4
- // fixes the root's tag before React draws.
1
+ // Not in react-prosemirror, whose node views draw their root: Wordgard fixes the root's tag before
2
+ // React draws.
5
3
  import { createContext } from "react";
6
4
  export const DecorationRootContext = createContext(null);
@@ -21,6 +21,7 @@ type Editor = EditorContextValue & {
21
21
  flushing: boolean;
22
22
  };
23
23
  export declare const editorOf: (wg: Wordgard) => Editor;
24
+ export declare const findEditor: (wg: Wordgard) => EditorContextValue | undefined;
24
25
  export declare const EditorContext: import("react").Context<EditorContextValue | null>;
25
26
  export declare const useEditorContext: () => EditorContextValue;
26
27
  export {};
@@ -1,6 +1,4 @@
1
- // Named after react-prosemirror's EditorContext, rewritten for Wordgard: the
2
- // editor, the state as of its last flush (react-prosemirror's state store),
3
- // and what the hooks register to run around its flush. One value per editor,
1
+ // Named after react-prosemirror's EditorContext, rewritten for Wordgard. One value per editor,
4
2
  // which never changes, so memoised components aren't scanned for it.
5
3
  import { createContext, useContext } from "react";
6
4
  import { flushSync } from "react-dom";
@@ -78,6 +76,8 @@ export const editorOf = (wg) => {
78
76
  editors.set(wg, editor);
79
77
  return editor;
80
78
  };
79
+ // The editor's value when react-wordgard drives it (WordgardEditor made it).
80
+ export const findEditor = (wg) => editors.get(wg);
81
81
  export const EditorContext = createContext(null);
82
82
  export const useEditorContext = () => {
83
83
  const context = useContext(EditorContext);
@@ -1,8 +1,6 @@
1
- // Named after our react-prosemirror fork's RenderStoreContext, rewritten for
2
- // Wordgard: what the view computes for rendering, held in one object per
3
- // content element and provided once, so its context value never changes and
4
- // memoised node views are never scanned for it. ReactDocTile writes it inside
5
- // Wordgard's flush, before React renders.
1
+ // Named after our react-prosemirror fork's RenderStoreContext, rewritten for Wordgard: one object
2
+ // per content element, which ReactDocTile writes inside the flush. Its value never changes, so
3
+ // memoised node views aren't scanned for it.
6
4
  import { createContext, useContext } from "react";
7
5
  const cells = new WeakMap();
8
6
  export const cellOf = (view) => {
@@ -1,9 +1,6 @@
1
- // The DOM events useEditorEventListener can listen to, and the handlers
2
- // ReactWordgard installs for them. Wordgard has a handler per event type, so
3
- // the types are fixed when the editor is created. Adding a handler makes
4
- // Wordgard's listener for the type non-passive: the events that block
5
- // scrolling (touch, wheel) aren't among them, nor the most frequent ones
6
- // (mousemove, pointer events), each of which would then walk the tiles.
1
+ // The DOM events useEditorEventListener can listen to. Wordgard fixes its handlers' event types at
2
+ // creation, and a handler makes its listener non-passive: scroll-blocking events (touch, wheel) and
3
+ // frequent ones (mousemove, pointer events) are left out.
7
4
  import { Wordgard } from "wordgard/editor";
8
5
  import { GardState } from "wordgard/state";
9
6
  export const editorEvents = [
@@ -1,6 +1,9 @@
1
1
  import { type AllHTMLAttributes, type ComponentType, type HTMLProps, type ReactElement, type ReactNode, type RefAttributes, type RefCallback } from "react";
2
2
  import type { Elt, Mark } from "wordgard/doc";
3
3
  import type { Tile } from "../wordgardInternals.js";
4
+ /**
5
+ * A React mark's props, for each run of an equal mark: `markProps.mark` is the document's mark.
6
+ */
4
7
  export type MarkComponentProps<E extends Element = HTMLElement> = AllHTMLAttributes<HTMLElement> & {
5
8
  markProps: {
6
9
  mark: Mark;
@@ -9,7 +12,12 @@ export type MarkComponentProps<E extends Element = HTMLElement> = AllHTMLAttribu
9
12
  };
10
13
  children: ReactNode;
11
14
  } & RefAttributes<E>;
15
+ /** `createMarkShape`'s options. */
12
16
  export type MarkShapeOptions = {
17
+ /**
18
+ * The component's root element, `span` by default, which plain Wordgard draws. It can't come from
19
+ * the mark type: a mark type's own `shape` is written before the type exists.
20
+ */
13
21
  element?: string;
14
22
  };
15
23
  type DrawProps = {
@@ -22,6 +30,9 @@ type MarkShape = {
22
30
  element: string;
23
31
  attributes: Record<string, string>;
24
32
  };
33
+ /**
34
+ * A mark's shape, for `Decoration.Mark.shape(MarkType, shape)` or a mark type's own `shape`.
35
+ */
25
36
  export declare const createMarkShape: <E extends Element = HTMLElement>(component: ComponentType<MarkComponentProps<E>>, { element }?: MarkShapeOptions) => MarkShape;
26
37
  export declare const isReactMark: (elt: Elt<unknown>) => boolean;
27
38
  export declare const drawMark: (elt: Elt<unknown>, props: DrawProps) => ReactElement<any, string | import("react").JSXElementConstructor<any>>;
@@ -1,10 +1,6 @@
1
- // Named after ReactWidgetType: a React mark is a mark's element shape (for
2
- // `Decoration.Mark.shape`, or a mark type's own spec), the element plain
3
- // Wordgard draws, registered as drawn by a component, which renders the
4
- // marked content as `children`. Wordgard's mark shapes are declarative, so the
5
- // registration is the reserved attribute React shapes use, which the element
6
- // Wordgard makes from the shape keeps. The props follow react-prosemirror's
7
- // MarkComponentProps.
1
+ // Named after ReactWidgetType. A React mark is a mark's element shape, registered as drawn by a
2
+ // component through the reserved attribute React shapes use: Wordgard's mark shapes are
3
+ // declarative. The props follow react-prosemirror's MarkComponentProps.
8
4
  import { createElement, } from "react";
9
5
  import { takesRef } from "../helpers/refs.js";
10
6
  import { idOf, reserved } from "./ReactShapeType.js";
@@ -12,6 +8,9 @@ import { idOf, reserved } from "./ReactShapeType.js";
12
8
  const draws = new Map();
13
9
  // By component, then root element, as React shapes are.
14
10
  const marks = new WeakMap();
11
+ /**
12
+ * A mark's shape, for `Decoration.Mark.shape(MarkType, shape)` or a mark type's own `shape`.
13
+ */
15
14
  export const createMarkShape = (component, { element = "span" } = {}) => {
16
15
  let registered = marks.get(component);
17
16
  if (!registered) {
@@ -1,5 +1,12 @@
1
1
  import { type AllHTMLAttributes, type ComponentType, type HTMLProps, type ReactElement, type ReactNode, type RefAttributes, type RefCallback } from "react";
2
2
  import { type Node as DocNode, Elt } from "wordgard/doc";
3
+ /**
4
+ * A React shape's props: `nodeProps`, the content as `children`, and Wordgard's attributes and
5
+ * `ref` for its root. The content goes in the `contentDOMRef` element, else in the root; in an
6
+ * atom, `children` is empty and a `contentDOMRef` throws. With `<DecorationRoot>` as the root, the
7
+ * attributes and `ref` are taken care of; a root drawn by hand spreads them onto itself (see [A
8
+ * root drawn by hand](https://github.com/stesura/react-wordgard#a-root-drawn-by-hand)).
9
+ */
3
10
  export type ShapeComponentProps<E extends Element = HTMLElement> = AllHTMLAttributes<HTMLElement> & {
4
11
  nodeProps: {
5
12
  node: DocNode;
@@ -8,6 +15,11 @@ export type ShapeComponentProps<E extends Element = HTMLElement> = AllHTMLAttrib
8
15
  };
9
16
  children: ReactNode;
10
17
  } & RefAttributes<E>;
18
+ /**
19
+ * What `createShape` returns: for `Decoration.Tag.shape`, a node's shape, its root the node type's
20
+ * own outer element, an atom where the type's shape is. `of` gives the shape with `element` for its
21
+ * root: for `Decoration.Point.shape`, or a root other than the type's.
22
+ */
11
23
  export type ReactShape = ((tag: DocNode.Tag) => Elt) & {
12
24
  of: (element: string, options?: {
13
25
  atom?: boolean;
@@ -20,6 +32,10 @@ type DrawProps = {
20
32
  children: ReactNode;
21
33
  ref: RefCallback<Element>;
22
34
  };
35
+ /**
36
+ * A node's shape, for `Decoration.Tag.shape(NodeType, shape)`. `shape.of(element)` is the shape
37
+ * with another root element, also for `Decoration.Point.shape`.
38
+ */
23
39
  export declare const createShape: <E extends Element = HTMLElement>(component: ComponentType<ShapeComponentProps<E>>) => ReactShape;
24
40
  export declare const idOf: (elt: Elt<unknown>) => string | null;
25
41
  export declare const isReactShape: (elt: Elt<unknown>) => boolean;
@@ -1,14 +1,8 @@
1
- // Named after ReactWidgetType: a React shape is a real Wordgard `Elt`, the
2
- // shape plain Wordgard draws, registered as drawn by a component, which renders
3
- // the content as `children`. Wordgard resolves decorations on the Elt before
4
- // React renders (`target` selectors match its tag), so its tag is known up
5
- // front: `createShape` gives `Decoration.Tag.shape` a function of the tag, which
6
- // takes it from the tag's node type, per node (a heading's level). Without a
7
- // hole, as for the type's own shape, it draws an atom. Wordgard copies an Elt
8
- // when it adds attributes or wraps it, so the registration is a reserved
9
- // attribute, which every copy keeps; React never renders it. The props follow
10
- // react-prosemirror's node views (`nodeProps`, `contentDOMRef`, a forwarded
11
- // ref), named after the decoration: Wordgard has no node views.
1
+ // Named after ReactWidgetType. A React shape is a real Wordgard `Elt`, registered as drawn by a
2
+ // component through a reserved attribute, which every copy Wordgard makes of it keeps and React
3
+ // never renders. Its tag is fixed before React renders (`target` selectors match it), so
4
+ // `createShape` gives `Decoration.Tag.shape` a function of the tag. The props follow
5
+ // react-prosemirror's node views (`nodeProps`, `contentDOMRef`, a forwarded ref).
12
6
  import { createElement, } from "react";
13
7
  import { Attributes, Elt } from "wordgard/doc";
14
8
  import { ignoresMutation } from "../contexts/DecorationContext.js";
@@ -18,6 +12,10 @@ const draws = new Map();
18
12
  // By component: calling createShape again with one gives the same shape, so
19
13
  // Wordgard sees no configuration change and the registry doesn't grow.
20
14
  const shapes = new WeakMap();
15
+ /**
16
+ * A node's shape, for `Decoration.Tag.shape(NodeType, shape)`. `shape.of(element)` is the shape
17
+ * with another root element, also for `Decoration.Point.shape`.
18
+ */
21
19
  export const createShape = (component) => {
22
20
  const found = shapes.get(component);
23
21
  if (found)
@@ -1,13 +1,23 @@
1
1
  import { type AllHTMLAttributes, type ComponentType, type HTMLProps, type ReactElement, type RefAttributes, type RefCallback } from "react";
2
2
  import { Attributes, Elt } from "wordgard/doc";
3
3
  import { Widget } from "wordgard/editor";
4
+ /**
5
+ * A React widget's props: its `value`, and, for a widget drawing a node, the node's attributes for
6
+ * its root.
7
+ */
4
8
  export type WidgetComponentProps<Param, E extends Element = HTMLElement> = Omit<AllHTMLAttributes<HTMLElement>, "value"> & {
5
9
  value: Param;
6
10
  } & RefAttributes<E>;
11
+ /** `createWidgetType`'s spec: Wordgard's widget spec, with a component in place of `render`. */
7
12
  export type WidgetTypeSpec<Param, E extends Element = HTMLElement> = Omit<Widget.Spec<Param>, "render"> & {
8
13
  component: ComponentType<WidgetComponentProps<Param, E>>;
14
+ /**
15
+ * The root `DecorationRoot` draws in the component, `span` by default. Wordgard doesn't look at a
16
+ * widget's element, so it's the component's choice.
17
+ */
9
18
  element?: string;
10
19
  };
20
+ /** A widget type whose widgets, `type.of(value)`, the component draws. */
11
21
  export declare const createWidgetType: <Param, E extends Element = HTMLElement>(spec: WidgetTypeSpec<Param, E>) => Widget.Type<Param>;
12
22
  export declare const createWidgetTypeWithRender: <Param, E extends Element = HTMLElement>(spec: WidgetTypeSpec<Param, E> & Pick<Widget.Spec<Param>, "render">) => Widget.Type<Param>;
13
23
  export declare const isReactWidget: (widget: Widget) => boolean;
@@ -1,11 +1,8 @@
1
- // Named after react-prosemirror's ReactWidgetType, rewritten for Wordgard: a
2
- // React widget type is a real Wordgard widget type, made by Widget.define with
3
- // the same spec, drawn by its component in the editor's own React tree. As
4
- // in react-prosemirror, the component forwards its ref to its root element,
5
- // which becomes the widget's DOM. Wordgard ignores what the component changes
6
- // inside that element, so it may re-render on its own, but not swap the
7
- // element itself: the parent's tile would put the old one back. An editable
8
- // one the user edits keeps the edit, where Wordgard would redraw it.
1
+ // Named after react-prosemirror's ReactWidgetType, rewritten for Wordgard: a real Wordgard widget
2
+ // type (Widget.define, same spec), drawn by its component in the editor's React tree. Its root,
3
+ // which the component forwards its ref to, is the widget's DOM: the component may re-render inside
4
+ // it, but not swap it, or the parent's tile puts the old one back. An editable one the user edits
5
+ // keeps the edit, where Wordgard would redraw it.
9
6
  import { createElement, } from "react";
10
7
  import { Attributes, Elt } from "wordgard/doc";
11
8
  import { Widget } from "wordgard/editor";
@@ -16,6 +13,7 @@ const components = new WeakMap();
16
13
  // Widget.define needs a `render`, which ReactWordgard never calls: only plain
17
14
  // Wordgard, given a React widget, draws this.
18
15
  const placeholder = () => document.createElement("span");
16
+ /** A widget type whose widgets, `type.of(value)`, the component draws. */
19
17
  export const createWidgetType = (spec) => createWidgetTypeWithRender({ ...spec, render: placeholder });
20
18
  // For the tests comparing ReactWordgard with plain Wordgard, which draws
21
19
  // `render`.
@@ -1,5 +1,8 @@
1
1
  import { type AllHTMLAttributes, type ComponentType, type HTMLProps, type ReactElement, type ReactNode, type RefAttributes, type RefCallback } from "react";
2
2
  import { type Node as DocNode, Elt } from "wordgard/doc";
3
+ /**
4
+ * A React wrapper's props: as a shape's, without `contentDOMRef`. `children` is what it wraps.
5
+ */
3
6
  export type WrapperComponentProps<E extends Element = HTMLElement> = AllHTMLAttributes<HTMLElement> & {
4
7
  nodeProps: {
5
8
  node: DocNode;
@@ -7,7 +10,12 @@ export type WrapperComponentProps<E extends Element = HTMLElement> = AllHTMLAttr
7
10
  };
8
11
  children: ReactNode;
9
12
  } & RefAttributes<E>;
13
+ /** `createWrapper`'s options. */
10
14
  export type WrapperOptions = {
15
+ /**
16
+ * The component's root element, `div` by default: `target` selectors match it, and plain Wordgard
17
+ * draws it. `span` around an inline node.
18
+ */
11
19
  element?: string;
12
20
  };
13
21
  type DrawProps = {
@@ -16,6 +24,7 @@ type DrawProps = {
16
24
  children: ReactNode;
17
25
  ref: RefCallback<Element>;
18
26
  };
27
+ /** A wrapper, for `Decoration.Tag.wrapper` and `Decoration.Point.wrapper`. */
19
28
  export declare const createWrapper: <E extends Element = HTMLElement>(component: ComponentType<WrapperComponentProps<E>>, { element }?: WrapperOptions) => Elt;
20
29
  export declare const isReactWrapper: (elt: Elt<unknown>) => boolean;
21
30
  export declare const drawWrapper: (elt: Elt<unknown>, props: DrawProps) => ReactElement<any, string | import("react").JSXElementConstructor<any>>;