Skip to content

Commit 0c143f3

Browse files
authored
Update docs for shuffle@0.2.0 (and fixes hoverDecorations API) (#19)
1 parent 297ffe7 commit 0c143f3

7 files changed

Lines changed: 187 additions & 122 deletions

File tree

.yarn/versions/5fb3719b.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
releases:
2+
"@pitter-patter/shuffle": minor

packages/docs/content/docs/shuffle/quick-start.mdx

Lines changed: 53 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -90,54 +90,27 @@ const editorState = EditorState.create({
9090
});
9191
```
9292

93-
## Configure drag handles
93+
## Configure hover decorations
9494

95-
Some editor components, like images, can be easily dragged and resized on their own. Others, like
96-
paragraphs, benefit from a drag handle to provide an easy target to click and move. To add drag
97-
handles pass a record of drag handles to the shuffle plugin. These should be React ProseMirror
98-
widget components.
95+
In schemas that can have deeply nested nodes, it can be helpful to use borders or highlights to
96+
indicate to the user which nodes are being hovered over.
9997

100-
The example below creates a `ParagraphHandle` widget that positions a handle to the top left of an
101-
element, and adds it to all paragraph nodes.
98+
The `hoverDecorations` argument to the shuffle plugin creator will be called with each hovered node
99+
to determine whether to render a node decoration.
102100

103101
```tsx
104-
import {
105-
reactKeys,
106-
useEditorEffect,
107-
type WidgetViewComponentProps,
108-
} from "@handlewithcare/react-prosemirror";
102+
import { reactKeys } from "@handlewithcare/react-prosemirror";
109103
import { shuffle } from "@pitter-patter/shuffle";
104+
import { Decoration } from "prosemirror-view";
105+
import { Node } from "prosemirror-model";
110106

111-
function ParagraphHandle({ widget, ref, getPos, ...props }: WidgetViewComponentProps) {
112-
const [top, setTop] = useState(0);
113-
const [left, setLeft] = useState(0);
107+
function hoverDecorations(from: number, to: number, node: Node) {
108+
// Return null to skip decorations for a given node
109+
if (node.type.name === "image") return null;
114110

115-
useEditorEffect(
116-
(view) => {
117-
const viewRect = view.dom.getBoundingClientRect();
118-
const coords = view.coordsAtPos(widget.spec.nodePos, 1);
119-
setTop(coords.top - viewRect.top);
120-
setLeft(coords.left - viewRect.left + (widget.spec.nodeDepth - 1) * 24);
121-
},
122-
[widget.spec.nodePos, widget.spec.nodeDepth],
123-
);
124-
125-
return (
126-
<div
127-
ref={ref}
128-
{...props}
129-
contentEditable={false}
130-
style={{
131-
position: "absolute",
132-
backgroundColor: "lightblue",
133-
transform: "translateY(-1.5rem)",
134-
top,
135-
left,
136-
}}
137-
>
138-
{name}
139-
</div>
140-
);
111+
return Decoration.node(from, to, {
112+
class: "shuffle-hover-block",
113+
});
141114
}
142115

143116
const editorState = EditorState.create({
@@ -146,22 +119,20 @@ const editorState = EditorState.create({
146119
plugins: [
147120
reactKeys(),
148121
shuffle({
149-
dragHandles: {
150-
paragraph: ParagraphHandle,
151-
},
122+
hoverDecorations,
152123
}),
153124
],
154125
});
155126
```
156127

157-
## Wrap your ProseMirror component with the `ShuffleSkeleton` and add `ResizeHandles`
128+
## Wrap your ProseMirror component with the `ShuffleSkeleton` and add `ResizeHandles` and `DragHandles`
158129

159130
Shuffle provides a `ShuffleSkeleton` component that wraps your `ProseMirrorDoc`. It renders
160131
Shuffle's grid skeleton, and must be rendered for resize and reposition behaviors to work correctly.
161132
The component should be a direct parent of the `ProseMirrorDoc` component.
162133

163134
To add resize handles to your elements, include the `ResizeHandles` component as a child of your
164-
`ShuffleSkeleton`.
135+
`ShuffleSkeleton`. Likewise, include the `DragHandles` component to render drag handles.
165136

166137
```tsx
167138
function Editor() {
@@ -170,6 +141,7 @@ function Editor() {
170141
<ShuffleSkeleton>
171142
<ProseMirrorDoc />
172143
<ResizeHandles />
144+
<DragHandles />
173145
</ShuffleSkeleton>
174146
</ProseMirror>
175147
);
@@ -210,7 +182,9 @@ interface Props {
210182
}
211183

212184
function ResizeHandle({ styles, onPointerDown }) {
213-
return <button type="button" styles={styles} onPointerDown={onPointerDown} />;
185+
return (
186+
<button type="button" className="resize-handle" styles={styles} onPointerDown={onPointerDown} />
187+
);
214188
}
215189

216190
function Editor() {
@@ -224,3 +198,35 @@ function Editor() {
224198
);
225199
}
226200
```
201+
202+
Similarly, the `DragHandles` component optionally takes a `handleComponent` prop that will be used
203+
instead of the default light blue button:
204+
205+
```tsx
206+
import { DragHandles } from "@pitter-patter/shuffle";
207+
import { EventHandler, PointerDown } from "react";
208+
209+
interface Props {
210+
style: { top: number; left: number };
211+
onPointerDown: EventHandler<PointerDown>;
212+
}
213+
214+
function DragHandle({ styles, onPointerDown, node }) {
215+
return (
216+
<button type="button" className="drag-handle" styles={styles} onPointerDown={onPointerDown}>
217+
{node.type.name[0].toUpperCase() + node.type.name.slice(1)}
218+
</button>
219+
);
220+
}
221+
222+
function Editor() {
223+
return (
224+
<ProseMirror defaultState={editorState}>
225+
<ShuffleSkeleton>
226+
<ProseMirrorDoc />
227+
<DragHandles handleComponent={DragHandle} />
228+
</ShuffleSkeleton>
229+
</ProseMirror>
230+
);
231+
}
232+
```

packages/docs/content/docs/shuffle/reference.mdx

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,16 @@ be set on the row and container node specs.
6969

7070
```ts
7171
interface ShufflePluginOptions {
72-
dragHandles?: Record<string, ComponentType<WidgetViewComponentProps>>;
72+
hoverDecorations?: (from: number, to: number, node: Node) => Decoration | null;
7373
}
7474
```
7575

76-
Options to be passed to `shuffle`. Can be used to provide drag handle widget components for specific
77-
node views.
76+
Options to be passed to `shuffle`. Can be used to provide hover decorations.
7877

7978
## `shuffle`
8079

8180
```ts
82-
function shuffle({ dragHandles }: ShufflePluginOptions = {}): Plugin<ShufflePluginState>;
81+
function shuffle({ hoverDecorations }: ShufflePluginOptions = {}): Plugin<ShufflePluginState>;
8382
```
8483

8584
A ProseMirror plugin factory. Manages decorations, state, and event listeners necessary for
@@ -160,6 +159,37 @@ the selected node and whether to create a handler for the start or end handler.
160159

161160
It returns an event handler that can be added to the `"pointerdown"` event.
162161

162+
## `DragHandles`
163+
164+
```ts
165+
function DragHandles(props: {
166+
handleComponent?: ComponentType<{
167+
style: { top: number; left: number };
168+
onPointerDown: EventHandler<SyntheticPointerEvent>;
169+
node: Node;
170+
}>;
171+
}): JSX.Element;
172+
```
173+
174+
A React component that renders the drag handles. This component will render a drag handle for each
175+
node that the pointer is currently hovering over. It should be a descendant of the `ProseMirror`
176+
component. The `handleComponent` prop can be used to provide a custom handle implementation.
177+
178+
Example usage:
179+
180+
```tsx
181+
function Editor() {
182+
return (
183+
<ProseMirror defaultState={editorState}>
184+
<ShuffleSkeleton>
185+
<ProseMirrorDoc />
186+
<DragHandles />
187+
</ShuffleSkeleton>
188+
</ProseMirror>
189+
);
190+
}
191+
```
192+
163193
## `supportsResize`
164194

165195
```ts

packages/docs/src/components/demos/shuffle.tsx

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -83,26 +83,18 @@ const nodeViewComponents = {
8383
image: Image,
8484
};
8585

86-
function hoverDeco(name: string) {
87-
return function (from: number, to: number) {
88-
return Decoration.node(from, to, {
89-
class: "shuffle-hover-block",
90-
"data-shuffle-demo-node-name": name,
91-
});
92-
};
86+
function hoverDecorations(from: number, to: number) {
87+
return Decoration.node(from, to, {
88+
class: "shuffle-hover-block",
89+
});
9390
}
9491

9592
const editorState = EditorState.create({
9693
doc,
9794
plugins: [
9895
reactKeys(),
9996
shuffle({
100-
hoverDecorations: {
101-
paragraph: hoverDeco("Paragraph"),
102-
container: hoverDeco("Container"),
103-
row: hoverDeco("Row"),
104-
image: hoverDeco("Image"),
105-
},
97+
hoverDecorations,
10698
}),
10799
keymap(baseKeymap),
108100
],

0 commit comments

Comments
 (0)