Skip to content

Commit 6600000

Browse files
committed
Add hoverOnly option to ClickToEditOptions
Allow click-to-edit to be conditionally enabled only on devices that support hover (non-touch devices), using window.matchMedia('(hover: hover)'). This helps avoid overlay interference on touch devices.
1 parent 4e89ab6 commit 6600000

3 files changed

Lines changed: 62 additions & 11 deletions

File tree

docs/content-link.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,12 +200,26 @@ There are two ways to enable click-to-edit mode:
200200
<ContentLink enableClickToEdit={true} />
201201
```
202202

203-
Or with scroll-to-nearest option:
203+
Or with additional options:
204204

205205
```jsx
206+
// Scroll to nearest editable element if none is visible
206207
<ContentLink enableClickToEdit={{ scrollToNearestTarget: true }} />
208+
209+
// Only enable on devices with hover capability (non-touch)
210+
<ContentLink enableClickToEdit={{ hoverOnly: true }} />
211+
212+
// Combine both options
213+
<ContentLink enableClickToEdit={{ hoverOnly: true, scrollToNearestTarget: true }} />
207214
```
208215

216+
**Available options (`ClickToEditOptions`):**
217+
218+
| Option | Type | Default | Description |
219+
| ------ | ---- | ------- | ----------- |
220+
| `scrollToNearestTarget` | `boolean` | `false` | Automatically scroll to the nearest editable element if none is currently visible in the viewport |
221+
| `hoverOnly` | `boolean` | `false` | Only enable click-to-edit on devices that support hover (non-touch). Uses `window.matchMedia('(hover: hover)')` to detect hover capability. On touch-only devices, users can still toggle manually with Alt/Option key |
222+
209223
This enables click-to-edit overlays immediately and keeps them visible.
210224

211225
### 2. Via keyboard shortcut (temporary)
@@ -245,7 +259,7 @@ The `<ContentLink />` component accepts the following props:
245259
| ------------------- | ----------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
246260
| `onNavigateTo` | `(path: string) => void` | - | Callback when [Web Previews plugin](https://www.datocms.com/marketplace/plugins/i/datocms-plugin-web-previews) requests navigation to a different page |
247261
| `currentPath` | `string` | - | Current pathname to sync with [Web Previews plugin](https://www.datocms.com/marketplace/plugins/i/datocms-plugin-web-previews) |
248-
| `enableClickToEdit` | `true \| { scrollToNearestTarget: true }` | - | Enable click-to-edit overlays on mount. Pass `true` or an object with options. If undefined, click-to-edit is disabled |
262+
| `enableClickToEdit` | `boolean \| ClickToEditOptions` | - | Enable click-to-edit overlays on mount. Pass `true` or an object with options. If `false`/`undefined`, click-to-edit is disabled (use Alt/Option key to toggle) |
249263
| `stripStega` | `boolean` | - | Whether to strip stega encoding from text nodes after stamping |
250264
| `root` | `React.RefObject<HTMLElement>` | - | Ref to limit scanning to this root element instead of the entire document |
251265

src/ContentLink/index.tsx

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,30 @@
22

33
import { useEffect } from 'react';
44
import {
5+
type ClickToEditOptions,
56
type UseContentLinkOptions,
67
useContentLink,
78
} from '../useContentLink/index.js';
89

910
export type ContentLinkProps = Omit<UseContentLinkOptions, 'enabled'> & {
1011
/** Current pathname to sync with Web Previews plugin */
1112
currentPath?: string;
12-
/** Enable click-to-edit on mount. Pass true for default behavior or an object with scrollToNearestTarget. If undefined or false, click-to-edit is disabled. */
13-
enableClickToEdit?: boolean | { scrollToNearestTarget: true };
13+
/**
14+
* Whether to enable click-to-edit overlays on mount, or options to configure them.
15+
*
16+
* - `true`: Enable click-to-edit mode immediately
17+
* - `{ scrollToNearestTarget: true }`: Enable and scroll to nearest editable if none visible
18+
* - `{ hoverOnly: true }`: Only enable on devices with hover capability (non-touch)
19+
* - `false`/`undefined`: Don't enable automatically (use Alt/Option key to toggle)
20+
*
21+
* @example
22+
* ```tsx
23+
* <ContentLink enableClickToEdit={true} />
24+
* <ContentLink enableClickToEdit={{ scrollToNearestTarget: true }} />
25+
* <ContentLink enableClickToEdit={{ hoverOnly: true, scrollToNearestTarget: true }} />
26+
* ```
27+
*/
28+
enableClickToEdit?: boolean | ClickToEditOptions;
1429
/** Whether to strip stega encoding from text nodes after stamping. */
1530
stripStega?: boolean;
1631
};

src/useContentLink/index.ts

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,36 @@ export type UseContentLinkOptions = {
2929
root?: React.RefObject<HTMLElement>;
3030
};
3131

32+
export interface ClickToEditOptions {
33+
/**
34+
* Whether to automatically scroll to the nearest editable element if none
35+
* is currently visible in the viewport when click-to-edit mode is enabled.
36+
*
37+
* @default false
38+
*/
39+
scrollToNearestTarget?: boolean;
40+
41+
/**
42+
* Only enable click-to-edit on devices that support hover (i.e., non-touch devices).
43+
* Uses `window.matchMedia('(hover: hover)')` to detect hover capability.
44+
*
45+
* This is useful to avoid showing overlays on touch devices where they may
46+
* interfere with normal scrolling and tapping behavior.
47+
*
48+
* When set to `true` on a touch-only device, click-to-edit will not be
49+
* automatically enabled, but users can still toggle it manually using
50+
* the Alt/Option key.
51+
*
52+
* @default false
53+
*/
54+
hoverOnly?: boolean;
55+
}
56+
3257
export type UseContentLinkResult = {
3358
/** The controller instance, or null if disabled */
3459
controller: Controller | null;
3560
/** Enable click-to-edit overlays */
36-
enableClickToEdit: (options?: { scrollToNearestTarget: boolean }) => void;
61+
enableClickToEdit: (options?: ClickToEditOptions) => void;
3762
/** Disable click-to-edit overlays */
3863
disableClickToEdit: () => void;
3964
/** Check if click-to-edit is enabled */
@@ -118,12 +143,9 @@ export function useContentLink(
118143
}, [enabled, root]);
119144

120145
// Stable method references that call through to the controller
121-
const enableClickToEdit = useCallback(
122-
(opts?: { scrollToNearestTarget: boolean }) => {
123-
controllerRef.current?.enableClickToEdit(opts);
124-
},
125-
[],
126-
);
146+
const enableClickToEdit = useCallback((opts?: ClickToEditOptions) => {
147+
controllerRef.current?.enableClickToEdit(opts);
148+
}, []);
127149

128150
const disableClickToEdit = useCallback(() => {
129151
controllerRef.current?.disableClickToEdit();

0 commit comments

Comments
 (0)