@datocms/svelte 4.2.3 → 4.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/package/components/ContentLink/ContentLink.svelte +40 -0
- package/package/components/ContentLink/ContentLink.svelte.d.ts +40 -0
- package/package/components/ContentLink/README.md +360 -0
- package/package/components/Head/Head.svelte.d.ts +1 -1
- package/package/components/Image/Image.svelte.d.ts +19 -19
- package/package/components/NakedImage/NakedImage.svelte.d.ts +9 -9
- package/package/components/StructuredText/Node.svelte.d.ts +4 -4
- package/package/components/StructuredText/StructuredText.svelte.d.ts +1 -1
- package/package/components/StructuredText/utils/Lines.svelte.d.ts +1 -1
- package/package/components/VideoPlayer/VideoPlayer.svelte.d.ts +3 -3
- package/package/index.d.ts +4 -1
- package/package/index.js +2 -0
- package/package/stores/querySubscription/index.d.ts +0 -1
- package/package.json +13 -3
package/README.md
CHANGED
|
@@ -37,6 +37,7 @@ A set of components to work faster with [DatoCMS](https://www.datocms.com/) in S
|
|
|
37
37
|
|
|
38
38
|
Components:
|
|
39
39
|
|
|
40
|
+
- [`<ContentLink />` for Visual Editing with click-to-edit overlays](src/lib/components/ContentLink)
|
|
40
41
|
- [`<Image />` and `<NakedImage />`](src/lib/components/Image)
|
|
41
42
|
- [`<VideoPlayer />`](src/lib/components/VideoPlayer)
|
|
42
43
|
- [`<StructuredText />`](src/lib/components/StructuredText)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<script>import { createController } from "@datocms/content-link";
|
|
2
|
+
import { onDestroy, onMount } from "svelte";
|
|
3
|
+
export let onNavigateTo = void 0;
|
|
4
|
+
export let currentPath = void 0;
|
|
5
|
+
export let enableClickToEdit = void 0;
|
|
6
|
+
export let stripStega = void 0;
|
|
7
|
+
export let root = void 0;
|
|
8
|
+
let controller = null;
|
|
9
|
+
let onNavigateToCallback = onNavigateTo;
|
|
10
|
+
$:
|
|
11
|
+
onNavigateToCallback = onNavigateTo;
|
|
12
|
+
onMount(() => {
|
|
13
|
+
controller = createController({
|
|
14
|
+
// Handle navigation requests from the Web Previews plugin
|
|
15
|
+
// Inside Visual mode, users can navigate to different URLs (like a browser bar)
|
|
16
|
+
// and the plugin will request the preview to navigate accordingly
|
|
17
|
+
// The callback is accessed via variable, so changes don't trigger recreation
|
|
18
|
+
onNavigateTo: onNavigateToCallback ? (path) => onNavigateToCallback?.(path) : void 0,
|
|
19
|
+
// Optionally limit scanning to a specific root
|
|
20
|
+
root,
|
|
21
|
+
// Control stega encoding stripping behavior
|
|
22
|
+
...stripStega !== void 0 ? { stripStega } : {}
|
|
23
|
+
});
|
|
24
|
+
if (enableClickToEdit !== void 0) {
|
|
25
|
+
controller.enableClickToEdit(
|
|
26
|
+
enableClickToEdit === true ? void 0 : enableClickToEdit
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
$:
|
|
31
|
+
if (currentPath !== void 0 && controller) {
|
|
32
|
+
controller.setCurrentPath(currentPath);
|
|
33
|
+
}
|
|
34
|
+
onDestroy(() => {
|
|
35
|
+
if (controller) {
|
|
36
|
+
controller.dispose();
|
|
37
|
+
controller = null;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
</script>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: {
|
|
4
|
+
/**
|
|
5
|
+
* Callback invoked when the Web Previews plugin requests navigation to a different URL.
|
|
6
|
+
* This is used for client-side routing integration.
|
|
7
|
+
*
|
|
8
|
+
* Example with SvelteKit: onNavigateTo={(path) => goto(path)}
|
|
9
|
+
*/ onNavigateTo?: ((path: string) => void) | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* Current pathname to sync with the Web Previews plugin.
|
|
12
|
+
* This keeps the plugin in sync with the current page being previewed.
|
|
13
|
+
*
|
|
14
|
+
* Example with SvelteKit: currentPath={$page.url.pathname}
|
|
15
|
+
*/ currentPath?: string | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Enable click-to-edit on mount. Pass true for default behavior or an object with scrollToNearestTarget.
|
|
18
|
+
* If undefined, click-to-edit is disabled and editors can use Alt/Option key for temporary activation.
|
|
19
|
+
*/ enableClickToEdit?: true | {
|
|
20
|
+
scrollToNearestTarget: true;
|
|
21
|
+
} | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Whether to strip stega encoding from text nodes after stamping.
|
|
24
|
+
*/ stripStega?: boolean | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* Ref to limit scanning to this root instead of document.
|
|
27
|
+
* Useful for limiting the scope of content link detection to a specific container.
|
|
28
|
+
*/ root?: ParentNode | undefined;
|
|
29
|
+
};
|
|
30
|
+
events: {
|
|
31
|
+
[evt: string]: CustomEvent<any>;
|
|
32
|
+
};
|
|
33
|
+
slots: {};
|
|
34
|
+
};
|
|
35
|
+
export type ContentLinkProps = typeof __propDef.props;
|
|
36
|
+
export type ContentLinkEvents = typeof __propDef.events;
|
|
37
|
+
export type ContentLinkSlots = typeof __propDef.slots;
|
|
38
|
+
export default class ContentLink extends SvelteComponent<ContentLinkProps, ContentLinkEvents, ContentLinkSlots> {
|
|
39
|
+
}
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
# ContentLink component for Visual Editing
|
|
2
|
+
|
|
3
|
+
`<ContentLink />` is a Svelte component that enables **Visual Editing** for your DatoCMS content. It provides click-to-edit overlays that allow editors to click on any content element on your website to instantly open the DatoCMS editor and modify that specific field.
|
|
4
|
+
|
|
5
|
+
This component is built on top of the [`@datocms/content-link`](https://www.npmjs.com/package/@datocms/content-link) library and provides a seamless integration for Svelte and SvelteKit projects.
|
|
6
|
+
|
|
7
|
+
## What is Visual Editing?
|
|
8
|
+
|
|
9
|
+
Visual Editing transforms how content editors interact with your website. Instead of navigating through forms and fields in a CMS, editors can:
|
|
10
|
+
|
|
11
|
+
1. **See their content in context** - Preview exactly how content appears on the live site
|
|
12
|
+
2. **Click to edit** - Click directly on any text, image, or field to open the editor
|
|
13
|
+
3. **Navigate seamlessly** - Jump between pages in the preview, and the CMS follows along
|
|
14
|
+
4. **Get instant feedback** - Changes in the CMS are reflected immediately in the preview
|
|
15
|
+
|
|
16
|
+
This drastically improves the editing experience, especially for non-technical users who can now edit content without understanding the underlying CMS structure.
|
|
17
|
+
|
|
18
|
+
## Out-of-the-box features
|
|
19
|
+
|
|
20
|
+
- **Click-to-edit overlays**: Visual indicators showing which content is editable
|
|
21
|
+
- **Stega decoding**: Automatically detects and decodes editing metadata embedded in content
|
|
22
|
+
- **Keyboard shortcuts**: Hold Alt/Option to temporarily enable editing mode
|
|
23
|
+
- **Flash-all highlighting**: Show all editable areas at once for quick orientation
|
|
24
|
+
- **Bidirectional navigation**: Sync navigation between preview and DatoCMS editor
|
|
25
|
+
- **Framework-agnostic**: Works with SvelteKit or any routing solution
|
|
26
|
+
- **StructuredText integration**: Special support for complex structured content fields
|
|
27
|
+
- **[Web Previews plugin](https://www.datocms.com/marketplace/plugins/i/datocms-plugin-web-previews) integration**: Seamless integration with DatoCMS's editing interface
|
|
28
|
+
|
|
29
|
+
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
|
30
|
+
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
|
31
|
+
|
|
32
|
+
- [Installation](#installation)
|
|
33
|
+
- [Basic Setup](#basic-setup)
|
|
34
|
+
- [1. Fetch content with stega encoding](#1-fetch-content-with-stega-encoding)
|
|
35
|
+
- [2. Add ContentLink component to your app](#2-add-contentlink-component-to-your-app)
|
|
36
|
+
- [SvelteKit integration](#sveltekit-integration)
|
|
37
|
+
- [Enabling click-to-edit](#enabling-click-to-edit)
|
|
38
|
+
- [Flash-all highlighting](#flash-all-highlighting)
|
|
39
|
+
- [Props](#props)
|
|
40
|
+
- [StructuredText integration](#structuredtext-integration)
|
|
41
|
+
- [Edit groups with `data-datocms-content-link-group`](#edit-groups-with-data-datocms-content-link-group)
|
|
42
|
+
- [Edit boundaries with `data-datocms-content-link-boundary`](#edit-boundaries-with-data-datocms-content-link-boundary)
|
|
43
|
+
- [Manual overlays with `data-datocms-content-link-url`](#manual-overlays-with-data-datocms-content-link-url)
|
|
44
|
+
- [Low-level utilities](#low-level-utilities)
|
|
45
|
+
- [`decodeStega`](#decodestega)
|
|
46
|
+
- [`stripStega`](#stripstega)
|
|
47
|
+
- [Troubleshooting](#troubleshooting)
|
|
48
|
+
- [Click-to-edit overlays not appearing](#click-to-edit-overlays-not-appearing)
|
|
49
|
+
- [Navigation not syncing with Web Previews plugin](#navigation-not-syncing-with-web-previews-plugin)
|
|
50
|
+
- [StructuredText blocks not clickable](#structuredtext-blocks-not-clickable)
|
|
51
|
+
|
|
52
|
+
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npm install --save @datocms/svelte
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The package includes `@datocms/content-link` as a dependency, which provides the underlying controller for Visual Editing functionality.
|
|
61
|
+
|
|
62
|
+
## Basic Setup
|
|
63
|
+
|
|
64
|
+
Visual Editing requires two steps:
|
|
65
|
+
|
|
66
|
+
### 1. Fetch content with stega encoding
|
|
67
|
+
|
|
68
|
+
When fetching content from DatoCMS, enable stega encoding to embed editing metadata:
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
import { executeQuery } from '@datocms/cda-client';
|
|
72
|
+
|
|
73
|
+
const query = `
|
|
74
|
+
query {
|
|
75
|
+
page {
|
|
76
|
+
title
|
|
77
|
+
content
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
`;
|
|
81
|
+
|
|
82
|
+
const result = await executeQuery(query, {
|
|
83
|
+
token: 'YOUR_API_TOKEN',
|
|
84
|
+
environment: 'main',
|
|
85
|
+
// Enable stega encoding
|
|
86
|
+
contentLink: 'v1',
|
|
87
|
+
// Set your site's base URL for editing links
|
|
88
|
+
baseEditingUrl: 'https://your-project.admin.datocms.com',
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The `contentLink` option encodes invisible metadata into text fields, while `baseEditingUrl` tells DatoCMS where your preview is hosted.
|
|
93
|
+
|
|
94
|
+
### 2. Add ContentLink component to your app
|
|
95
|
+
|
|
96
|
+
Add the `<ContentLink />` component to your app. It doesn't render any visible output but sets up the click-to-edit functionality:
|
|
97
|
+
|
|
98
|
+
```svelte
|
|
99
|
+
<script>
|
|
100
|
+
import { ContentLink } from '@datocms/svelte';
|
|
101
|
+
</script>
|
|
102
|
+
|
|
103
|
+
<ContentLink />
|
|
104
|
+
|
|
105
|
+
<!-- Your content here -->
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
That's it! The component will automatically detect editable content and create interactive overlays.
|
|
109
|
+
|
|
110
|
+
## SvelteKit integration
|
|
111
|
+
|
|
112
|
+
For SvelteKit projects, you can integrate with the routing system to enable full Web Previews plugin support:
|
|
113
|
+
|
|
114
|
+
```svelte
|
|
115
|
+
<script>
|
|
116
|
+
import { ContentLink } from '@datocms/svelte';
|
|
117
|
+
import { goto } from '$app/navigation';
|
|
118
|
+
import { page } from '$app/stores';
|
|
119
|
+
</script>
|
|
120
|
+
|
|
121
|
+
<ContentLink
|
|
122
|
+
onNavigateTo={(path) => goto(path)}
|
|
123
|
+
currentPath={$page.url.pathname}
|
|
124
|
+
/>
|
|
125
|
+
|
|
126
|
+
<!-- Your content here -->
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
This integration enables:
|
|
130
|
+
- **Navigation from plugin**: When editors navigate to a different URL in the Visual Editing mode, your preview updates accordingly
|
|
131
|
+
- **Current path sync**: The plugin knows which page is currently being previewed
|
|
132
|
+
|
|
133
|
+
## Enabling click-to-edit
|
|
134
|
+
|
|
135
|
+
Click-to-edit overlays are **not enabled by default**. Instead, editors can:
|
|
136
|
+
|
|
137
|
+
- **Hold Alt/Option key**: Temporarily enable click-to-edit mode while the key is held down
|
|
138
|
+
- **Release the key**: Disable click-to-edit mode when released
|
|
139
|
+
|
|
140
|
+
If you prefer to enable click-to-edit programmatically on mount, set the `enableClickToEdit` prop:
|
|
141
|
+
|
|
142
|
+
```svelte
|
|
143
|
+
<ContentLink enableClickToEdit={true} />
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Or with scroll-to-nearest option:
|
|
147
|
+
|
|
148
|
+
```svelte
|
|
149
|
+
<ContentLink enableClickToEdit={{ scrollToNearestTarget: true }} />
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Flash-all highlighting
|
|
153
|
+
|
|
154
|
+
The flash-all feature provides visual feedback by highlighting all editable elements on the page. This is useful for:
|
|
155
|
+
- Showing editors what content they can edit
|
|
156
|
+
- Debugging to verify Visual Editing is working correctly
|
|
157
|
+
- Onboarding new content editors
|
|
158
|
+
|
|
159
|
+
When you enable click-to-edit with the `scrollToNearestTarget` option, it triggers the flash-all effect:
|
|
160
|
+
|
|
161
|
+
```svelte
|
|
162
|
+
<ContentLink enableClickToEdit={{ scrollToNearestTarget: true }} />
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The `scrollToNearestTarget` parameter scrolls to the nearest editable element, useful on long pages.
|
|
166
|
+
|
|
167
|
+
## Props
|
|
168
|
+
|
|
169
|
+
| Prop | Type | Default | Description |
|
|
170
|
+
| ------------------- | ----------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
171
|
+
| `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 |
|
|
172
|
+
| `currentPath` | `string` | - | Current pathname to sync with [Web Previews plugin](https://www.datocms.com/marketplace/plugins/i/datocms-plugin-web-previews) |
|
|
173
|
+
| `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 |
|
|
174
|
+
| `stripStega` | `boolean` | - | Whether to strip stega encoding from text nodes after stamping |
|
|
175
|
+
| `root` | `ParentNode` | - | Root element to limit scanning to instead of the entire document |
|
|
176
|
+
|
|
177
|
+
## StructuredText integration
|
|
178
|
+
|
|
179
|
+
When rendering Structured Text fields, you'll want to make the entire structured text area clickable rather than just specific spans. DatoCMS provides special HTML attributes to control this behavior.
|
|
180
|
+
|
|
181
|
+
### Edit groups with `data-datocms-content-link-group`
|
|
182
|
+
|
|
183
|
+
Wrap your StructuredText component with a container that has the `data-datocms-content-link-group` attribute. This makes the entire area clickable to edit the structured text field:
|
|
184
|
+
|
|
185
|
+
```svelte
|
|
186
|
+
<script>
|
|
187
|
+
import { StructuredText } from '@datocms/svelte';
|
|
188
|
+
</script>
|
|
189
|
+
|
|
190
|
+
<div data-datocms-content-link-group>
|
|
191
|
+
<StructuredText data={content.structuredTextField} />
|
|
192
|
+
</div>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
This allows editors to click anywhere within the structured text content to edit it, rather than targeting small span elements.
|
|
196
|
+
|
|
197
|
+
### Edit boundaries with `data-datocms-content-link-boundary`
|
|
198
|
+
|
|
199
|
+
When your Structured Text contains embedded blocks, you'll want those blocks to open their own specific record editor instead of the structured text field editor. Use the `data-datocms-content-link-boundary` attribute to stop the upward traversal:
|
|
200
|
+
|
|
201
|
+
```svelte
|
|
202
|
+
<script>
|
|
203
|
+
import { StructuredText } from '@datocms/svelte';
|
|
204
|
+
import BlockComponent from './BlockComponent.svelte';
|
|
205
|
+
</script>
|
|
206
|
+
|
|
207
|
+
<div data-datocms-content-link-group>
|
|
208
|
+
<StructuredText
|
|
209
|
+
data={content.structuredTextField}
|
|
210
|
+
blocks={{
|
|
211
|
+
// Render custom blocks
|
|
212
|
+
myBlock: (props) => ({
|
|
213
|
+
component: BlockComponent,
|
|
214
|
+
props: {
|
|
215
|
+
block: props.record,
|
|
216
|
+
// Wrap the block with a boundary
|
|
217
|
+
useBoundary: true,
|
|
218
|
+
}
|
|
219
|
+
})
|
|
220
|
+
}}
|
|
221
|
+
/>
|
|
222
|
+
</div>
|
|
223
|
+
|
|
224
|
+
<!-- In BlockComponent.svelte -->
|
|
225
|
+
<div data-datocms-content-link-boundary>
|
|
226
|
+
<h2>{block.title}</h2>
|
|
227
|
+
<p>{block.description}</p>
|
|
228
|
+
</div>
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
In this example:
|
|
232
|
+
- Clicking on the main structured text content opens the structured text field editor
|
|
233
|
+
- Clicking on an embedded block opens that specific block's record editor
|
|
234
|
+
|
|
235
|
+
## Manual overlays with `data-datocms-content-link-url`
|
|
236
|
+
|
|
237
|
+
For non-text fields like booleans, numbers, dates, and JSON, the DatoCMS API cannot embed stega-encoded metadata. In these cases, you can manually specify the edit URL using the `data-datocms-content-link-url` attribute.
|
|
238
|
+
|
|
239
|
+
The recommended approach is to use the `_editingUrl` field available on all records:
|
|
240
|
+
|
|
241
|
+
```graphql
|
|
242
|
+
query {
|
|
243
|
+
product {
|
|
244
|
+
id
|
|
245
|
+
price
|
|
246
|
+
isActive
|
|
247
|
+
_editingUrl
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Then add the attribute to your element:
|
|
253
|
+
|
|
254
|
+
```svelte
|
|
255
|
+
<span data-datocms-content-link-url={product._editingUrl}>
|
|
256
|
+
${product.price}
|
|
257
|
+
</span>
|
|
258
|
+
|
|
259
|
+
<span data-datocms-content-link-url={product._editingUrl}>
|
|
260
|
+
{product.isActive ? 'Active' : 'Inactive'}
|
|
261
|
+
</span>
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
This ensures the URL format is always correct and adapts automatically to any future changes.
|
|
265
|
+
|
|
266
|
+
## Low-level utilities
|
|
267
|
+
|
|
268
|
+
The `@datocms/svelte` package re-exports utility functions from `@datocms/content-link` for working with stega-encoded content:
|
|
269
|
+
|
|
270
|
+
### `decodeStega`
|
|
271
|
+
|
|
272
|
+
Decodes stega-encoded content to extract editing metadata:
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
import { decodeStega } from '@datocms/svelte';
|
|
276
|
+
|
|
277
|
+
const text = "Hello, world!"; // Contains invisible stega data
|
|
278
|
+
const decoded = decodeStega(text);
|
|
279
|
+
|
|
280
|
+
if (decoded) {
|
|
281
|
+
console.log('Editing URL:', decoded.url);
|
|
282
|
+
console.log('Clean text:', decoded.cleanText);
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### `stripStega`
|
|
287
|
+
|
|
288
|
+
Removes stega encoding from text, returning clean text:
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
import { stripStega } from '@datocms/svelte';
|
|
292
|
+
|
|
293
|
+
const text = "Hello, world!"; // Contains invisible stega data
|
|
294
|
+
const clean = stripStega(text);
|
|
295
|
+
|
|
296
|
+
console.log(clean); // "Hello, world!" without encoding
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
These utilities are useful when you need to:
|
|
300
|
+
- Extract clean text for meta tags or social sharing
|
|
301
|
+
- Check if content has stega encoding
|
|
302
|
+
- Debug Visual Editing issues
|
|
303
|
+
- Process stega-encoded content programmatically
|
|
304
|
+
|
|
305
|
+
## Troubleshooting
|
|
306
|
+
|
|
307
|
+
### Click-to-edit overlays not appearing
|
|
308
|
+
|
|
309
|
+
**Problem**: Overlays don't appear when clicking on content.
|
|
310
|
+
|
|
311
|
+
**Solutions**:
|
|
312
|
+
1. Verify stega encoding is enabled in your API calls:
|
|
313
|
+
```js
|
|
314
|
+
const result = await executeQuery(query, {
|
|
315
|
+
token: 'YOUR_API_TOKEN',
|
|
316
|
+
contentLink: 'v1',
|
|
317
|
+
baseEditingUrl: 'https://your-project.admin.datocms.com',
|
|
318
|
+
});
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
2. Check that `<ContentLink />` is mounted in your component tree
|
|
322
|
+
|
|
323
|
+
3. Ensure you've enabled click-to-edit mode:
|
|
324
|
+
```svelte
|
|
325
|
+
<ContentLink enableClickToEdit={true} />
|
|
326
|
+
```
|
|
327
|
+
Or hold Alt/Option key while browsing
|
|
328
|
+
|
|
329
|
+
4. Check browser console for errors
|
|
330
|
+
|
|
331
|
+
### Navigation not syncing with Web Previews plugin
|
|
332
|
+
|
|
333
|
+
**Problem**: When you navigate in your preview, the DatoCMS editor doesn't follow along.
|
|
334
|
+
|
|
335
|
+
**Solutions**:
|
|
336
|
+
1. Ensure you're providing both `onNavigateTo` and `currentPath` props:
|
|
337
|
+
```svelte
|
|
338
|
+
<ContentLink
|
|
339
|
+
onNavigateTo={(path) => goto(path)}
|
|
340
|
+
currentPath={$page.url.pathname}
|
|
341
|
+
/>
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
2. Verify `currentPath` updates when navigation occurs
|
|
345
|
+
|
|
346
|
+
3. Check that `baseEditingUrl` in your API calls matches your preview URL
|
|
347
|
+
|
|
348
|
+
### StructuredText blocks not clickable
|
|
349
|
+
|
|
350
|
+
**Problem**: Content within StructuredText blocks doesn't have click-to-edit overlays.
|
|
351
|
+
|
|
352
|
+
**Solutions**:
|
|
353
|
+
1. Wrap StructuredText with `data-datocms-content-link-group`:
|
|
354
|
+
```svelte
|
|
355
|
+
<div data-datocms-content-link-group>
|
|
356
|
+
<StructuredText data={content} />
|
|
357
|
+
</div>
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
2. Add `data-datocms-content-link-boundary` to custom blocks to prevent them from bubbling to the parent field
|
|
@@ -46,7 +46,7 @@ export type FaviconTag = SeoMetaTag | SeoLinkTag;
|
|
|
46
46
|
export type SeoOrFaviconTag = SeoTag | FaviconTag;
|
|
47
47
|
declare const __propDef: {
|
|
48
48
|
props: {
|
|
49
|
-
data?:
|
|
49
|
+
data?: Array<GenericTag | SeoOrFaviconTag>;
|
|
50
50
|
};
|
|
51
51
|
events: {
|
|
52
52
|
[evt: string]: CustomEvent<any>;
|
|
@@ -4,17 +4,17 @@ import { type ResponsiveImageType } from '../NakedImage/utils';
|
|
|
4
4
|
declare const __propDef: {
|
|
5
5
|
props: {
|
|
6
6
|
/** The actual response you get from a DatoCMS `responsiveImage` GraphQL query */ data: ResponsiveImageType;
|
|
7
|
-
/** Additional CSS className for root node */ class?: string | null
|
|
8
|
-
/** Additional CSS class for the `<picture />` tag */ pictureClass?: string | null
|
|
9
|
-
/** Additional CSS class for the image inside the `<picture />` tag */ imgClass?: string | null
|
|
10
|
-
/** Additional CSS class for the placeholder element */ placeholderClass?: string | null
|
|
11
|
-
/** Duration (in ms) of the fade-in transition effect upoad image loading */ fadeInDuration?: number
|
|
12
|
-
/** Indicate at what percentage of the placeholder visibility the loading of the image should be triggered. A value of 0 means that as soon as even one pixel is visible, the callback will be run. A value of 1.0 means that the threshold isn't considered passed until every pixel is visible */ intersectionThreshold?: number
|
|
13
|
-
/** Margin around the placeholder. Can have values similar to the CSS margin property (top, right, bottom, left). The values can be percentages. This set of values serves to grow or shrink each side of the placeholder element's bounding box before computing intersections */ intersectionMargin?: string
|
|
14
|
-
/** Additional CSS rules to add to the root node */ style?: string | null
|
|
15
|
-
/** Additional CSS rules to add to the `<picture />` tag */ pictureStyle?: string | null
|
|
16
|
-
/** Additional CSS rules to add to the image inside the `<picture />` tag */ imgStyle?: string | null
|
|
17
|
-
/** Additional CSS rules to add to the placeholder element */ placeholderStyle?: string | null
|
|
7
|
+
/** Additional CSS className for root node */ class?: string | null;
|
|
8
|
+
/** Additional CSS class for the `<picture />` tag */ pictureClass?: string | null;
|
|
9
|
+
/** Additional CSS class for the image inside the `<picture />` tag */ imgClass?: string | null;
|
|
10
|
+
/** Additional CSS class for the placeholder element */ placeholderClass?: string | null;
|
|
11
|
+
/** Duration (in ms) of the fade-in transition effect upoad image loading */ fadeInDuration?: number;
|
|
12
|
+
/** Indicate at what percentage of the placeholder visibility the loading of the image should be triggered. A value of 0 means that as soon as even one pixel is visible, the callback will be run. A value of 1.0 means that the threshold isn't considered passed until every pixel is visible */ intersectionThreshold?: number;
|
|
13
|
+
/** Margin around the placeholder. Can have values similar to the CSS margin property (top, right, bottom, left). The values can be percentages. This set of values serves to grow or shrink each side of the placeholder element's bounding box before computing intersections */ intersectionMargin?: string;
|
|
14
|
+
/** Additional CSS rules to add to the root node */ style?: string | null;
|
|
15
|
+
/** Additional CSS rules to add to the `<picture />` tag */ pictureStyle?: string | null;
|
|
16
|
+
/** Additional CSS rules to add to the image inside the `<picture />` tag */ imgStyle?: string | null;
|
|
17
|
+
/** Additional CSS rules to add to the placeholder element */ placeholderStyle?: string | null;
|
|
18
18
|
/**
|
|
19
19
|
* The layout behavior of the image as the viewport changes size
|
|
20
20
|
*
|
|
@@ -24,33 +24,33 @@ declare const __propDef: {
|
|
|
24
24
|
* * `fixed`: the image dimensions will not change as the viewport changes (no responsiveness) similar to the native img element
|
|
25
25
|
* * `responsive`: the image will scale the dimensions down for smaller viewports and scale up for larger viewports
|
|
26
26
|
* * `fill`: image will stretch both width and height to the dimensions of the parent element, provided the parent element is `relative`
|
|
27
|
-
**/ layout?: "
|
|
28
|
-
/** Defines how the image will fit into its parent container when using layout="fill" */ objectFit?: CSS.PropertiesHyphen[
|
|
29
|
-
/** Defines how the image is positioned within its parent element when using layout="fill". */ objectPosition?: CSS.PropertiesHyphen[
|
|
30
|
-
/** Whether the component should use a blurred image placeholder */ usePlaceholder?: boolean
|
|
27
|
+
**/ layout?: "intrinsic" | "fixed" | "responsive" | "fill";
|
|
28
|
+
/** Defines how the image will fit into its parent container when using layout="fill" */ objectFit?: CSS.PropertiesHyphen["object-fit"];
|
|
29
|
+
/** Defines how the image is positioned within its parent element when using layout="fill". */ objectPosition?: CSS.PropertiesHyphen["object-position"];
|
|
30
|
+
/** Whether the component should use a blurred image placeholder */ usePlaceholder?: boolean;
|
|
31
31
|
/**
|
|
32
32
|
* The HTML5 `sizes` attribute for the image
|
|
33
33
|
*
|
|
34
34
|
* Learn more about srcset and sizes:
|
|
35
35
|
* -> https://web.dev/learn/design/responsive-images/#sizes
|
|
36
36
|
* -> https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-sizes
|
|
37
|
-
**/ sizes?:
|
|
37
|
+
**/ sizes?: HTMLImageElement["sizes"] | null;
|
|
38
38
|
/**
|
|
39
39
|
* When true, the image will be considered high priority. Lazy loading is automatically disabled, and fetchpriority="high" is added to the image.
|
|
40
40
|
* You should use the priority property on any image detected as the Largest Contentful Paint (LCP) element. It may be appropriate to have multiple priority images, as different images may be the LCP element for different viewport sizes.
|
|
41
41
|
* Should only be used when the image is visible above the fold.
|
|
42
|
-
**/ priority?: boolean
|
|
42
|
+
**/ priority?: boolean;
|
|
43
43
|
/**
|
|
44
44
|
* If `data` does not contain `srcSet`, the candidates for the `srcset` of the image will be auto-generated based on these width multipliers
|
|
45
45
|
*
|
|
46
46
|
* Default candidate multipliers are [0.25, 0.5, 0.75, 1, 1.5, 2, 3, 4]
|
|
47
|
-
**/ srcSetCandidates?: number[]
|
|
47
|
+
**/ srcSetCandidates?: number[];
|
|
48
48
|
/**
|
|
49
49
|
* Defines which referrer is sent when fetching the image
|
|
50
50
|
* Read more: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#referrerpolicy
|
|
51
51
|
*
|
|
52
52
|
* Defaults to `no-referrer-when-downgrade` to give more useful stats in DatoCMS Project Usages
|
|
53
|
-
**/ referrerPolicy?: ReferrerPolicy
|
|
53
|
+
**/ referrerPolicy?: ReferrerPolicy;
|
|
54
54
|
};
|
|
55
55
|
events: {
|
|
56
56
|
load: CustomEvent<any>;
|
|
@@ -3,34 +3,34 @@ import { type ResponsiveImageType } from './utils';
|
|
|
3
3
|
declare const __propDef: {
|
|
4
4
|
props: {
|
|
5
5
|
/** The actual response you get from a DatoCMS `responsiveImage` GraphQL query */ data: ResponsiveImageType;
|
|
6
|
-
/** Additional CSS className for the root <picture> tag */ pictureClass?: string | null
|
|
7
|
-
/** Additional CSS rules to add to the root <picture> tag */ pictureStyle?: string | null
|
|
8
|
-
/** Additional CSS className for the <img> tag */ imgClass?: string | null
|
|
9
|
-
/** Additional CSS rules to add to the <img> tag */ imgStyle?: string | null
|
|
10
|
-
/** Whether the component should use a blurred image placeholder */ usePlaceholder?: boolean
|
|
6
|
+
/** Additional CSS className for the root <picture> tag */ pictureClass?: string | null;
|
|
7
|
+
/** Additional CSS rules to add to the root <picture> tag */ pictureStyle?: string | null;
|
|
8
|
+
/** Additional CSS className for the <img> tag */ imgClass?: string | null;
|
|
9
|
+
/** Additional CSS rules to add to the <img> tag */ imgStyle?: string | null;
|
|
10
|
+
/** Whether the component should use a blurred image placeholder */ usePlaceholder?: boolean;
|
|
11
11
|
/**
|
|
12
12
|
* The HTML5 `sizes` attribute for the image
|
|
13
13
|
*
|
|
14
14
|
* Learn more about srcset and sizes:
|
|
15
15
|
* -> https://web.dev/learn/design/responsive-images/#sizes
|
|
16
16
|
* -> https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-sizes
|
|
17
|
-
**/ sizes?:
|
|
17
|
+
**/ sizes?: HTMLImageElement["sizes"] | null;
|
|
18
18
|
/**
|
|
19
19
|
* When true, the image will be considered high priority. Lazy loading is automatically disabled, and fetchpriority="high" is added to the image.
|
|
20
20
|
* You should use the priority property on any image detected as the Largest Contentful Paint (LCP) element. It may be appropriate to have multiple priority images, as different images may be the LCP element for different viewport sizes.
|
|
21
21
|
* Should only be used when the image is visible above the fold.
|
|
22
|
-
**/ priority?: boolean
|
|
22
|
+
**/ priority?: boolean;
|
|
23
23
|
/**
|
|
24
24
|
* If `data` does not contain `srcSet`, the candidates for the `srcset` of the image will be auto-generated based on these width multipliers
|
|
25
25
|
*
|
|
26
26
|
* Default candidate multipliers are [0.25, 0.5, 0.75, 1, 1.5, 2, 3, 4]
|
|
27
|
-
**/ srcSetCandidates?: number[]
|
|
27
|
+
**/ srcSetCandidates?: number[];
|
|
28
28
|
/**
|
|
29
29
|
* Defines which referrer is sent when fetching the image
|
|
30
30
|
* Read more: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#referrerpolicy
|
|
31
31
|
*
|
|
32
32
|
* Defaults to `no-referrer-when-downgrade` to give more useful stats in DatoCMS Project Usages
|
|
33
|
-
**/ referrerPolicy?: ReferrerPolicy
|
|
33
|
+
**/ referrerPolicy?: ReferrerPolicy;
|
|
34
34
|
};
|
|
35
35
|
events: {
|
|
36
36
|
load: CustomEvent<any>;
|
|
@@ -5,10 +5,10 @@ import type { PredicateComponentTuple } from '../..';
|
|
|
5
5
|
declare const __propDef: {
|
|
6
6
|
props: {
|
|
7
7
|
node: Node;
|
|
8
|
-
blocks: StructuredText[
|
|
9
|
-
inlineBlocks: StructuredText[
|
|
10
|
-
links: StructuredText[
|
|
11
|
-
components?: PredicateComponentTuple[]
|
|
8
|
+
blocks: StructuredText["blocks"];
|
|
9
|
+
inlineBlocks: StructuredText["inlineBlocks"];
|
|
10
|
+
links: StructuredText["links"];
|
|
11
|
+
components?: PredicateComponentTuple[];
|
|
12
12
|
};
|
|
13
13
|
events: {
|
|
14
14
|
[evt: string]: CustomEvent<any>;
|
|
@@ -4,7 +4,7 @@ import type { PredicateComponentTuple } from '../..';
|
|
|
4
4
|
declare const __propDef: {
|
|
5
5
|
props: {
|
|
6
6
|
/** The actual field value you get from DatoCMS **/ data?: StructuredText | Document | DastNode | null | undefined;
|
|
7
|
-
components?: PredicateComponentTuple[]
|
|
7
|
+
components?: PredicateComponentTuple[];
|
|
8
8
|
};
|
|
9
9
|
events: {
|
|
10
10
|
[evt: string]: CustomEvent<any>;
|
|
@@ -94,7 +94,7 @@ export declare const toNativeAttrValue: (propValue: any, propName: string) => an
|
|
|
94
94
|
import type MuxPlayerElement from '@mux/mux-player';
|
|
95
95
|
declare const __propDef: {
|
|
96
96
|
props: Partial<MuxPlayerProps> & {
|
|
97
|
-
data?: Video
|
|
97
|
+
data?: Video;
|
|
98
98
|
};
|
|
99
99
|
events: {
|
|
100
100
|
abort: UIEvent;
|
|
@@ -120,8 +120,8 @@ declare const __propDef: {
|
|
|
120
120
|
suspend: Event;
|
|
121
121
|
ended: Event;
|
|
122
122
|
error: ErrorEvent;
|
|
123
|
-
cuepointchange: Event | UIEvent | ProgressEvent<EventTarget> | ErrorEvent | ClipboardEvent | DragEvent | MouseEvent | FocusEvent | AnimationEvent | InputEvent |
|
|
124
|
-
cuepointschange: Event | UIEvent | ProgressEvent<EventTarget> | ErrorEvent | ClipboardEvent | DragEvent | MouseEvent | FocusEvent | AnimationEvent | InputEvent |
|
|
123
|
+
cuepointchange: Event | UIEvent | ProgressEvent<EventTarget> | ErrorEvent | ClipboardEvent | DragEvent | MouseEvent | PointerEvent | FocusEvent | AnimationEvent | InputEvent | ToggleEvent | CompositionEvent | FormDataEvent | KeyboardEvent | SecurityPolicyViolationEvent | SubmitEvent | TouchEvent | TransitionEvent | WheelEvent;
|
|
124
|
+
cuepointschange: Event | UIEvent | ProgressEvent<EventTarget> | ErrorEvent | ClipboardEvent | DragEvent | MouseEvent | PointerEvent | FocusEvent | AnimationEvent | InputEvent | ToggleEvent | CompositionEvent | FormDataEvent | KeyboardEvent | SecurityPolicyViolationEvent | SubmitEvent | TouchEvent | TransitionEvent | WheelEvent;
|
|
125
125
|
} & {
|
|
126
126
|
[evt: string]: CustomEvent<any>;
|
|
127
127
|
};
|
package/package/index.d.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import type { Node, CdaStructuredTextValue, CdaStructuredTextRecord, TypesafeCdaStructuredTextValue, Document as StructuredTextDocument } from 'datocms-structured-text-utils';
|
|
2
2
|
export { default as NakedImage } from './components/NakedImage/NakedImage.svelte';
|
|
3
3
|
export type { ResponsiveImageType } from './components/NakedImage/utils';
|
|
4
|
+
export { default as ContentLink } from './components/ContentLink/ContentLink.svelte';
|
|
4
5
|
export { default as Head } from './components/Head/Head.svelte';
|
|
5
6
|
export { default as Image } from './components/Image/Image.svelte';
|
|
6
7
|
export { default as StructuredText } from './components/StructuredText/StructuredText.svelte';
|
|
7
8
|
export { default as VideoPlayer } from './components/VideoPlayer/VideoPlayer.svelte';
|
|
8
9
|
export * from './stores/querySubscription';
|
|
9
|
-
export type {
|
|
10
|
+
export type { Controller } from '@datocms/content-link';
|
|
11
|
+
export { decodeStega, stripStega } from '@datocms/content-link';
|
|
12
|
+
export type { StructuredTextDocument, CdaStructuredTextValue, TypesafeCdaStructuredTextValue, CdaStructuredTextRecord };
|
|
10
13
|
export type PredicateComponentTuple = [
|
|
11
14
|
(n: Node) => boolean,
|
|
12
15
|
any
|
package/package/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { default as NakedImage } from './components/NakedImage/NakedImage.svelte';
|
|
2
|
+
export { default as ContentLink } from './components/ContentLink/ContentLink.svelte';
|
|
2
3
|
export { default as Head } from './components/Head/Head.svelte';
|
|
3
4
|
export { default as Image } from './components/Image/Image.svelte';
|
|
4
5
|
export { default as StructuredText } from './components/StructuredText/StructuredText.svelte';
|
|
5
6
|
export { default as VideoPlayer } from './components/VideoPlayer/VideoPlayer.svelte';
|
|
6
7
|
export * from './stores/querySubscription';
|
|
8
|
+
export { decodeStega, stripStega } from '@datocms/content-link';
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/// <reference types="svelte" />
|
|
2
1
|
import { type ChannelErrorData, type ConnectionStatus, type Options } from 'datocms-listen';
|
|
3
2
|
export type SubscribeToQueryOptions<QueryResult, QueryVariables> = Omit<Options<QueryResult, QueryVariables>, 'onStatusChange' | 'onUpdate' | 'onChannelError'>;
|
|
4
3
|
export type EnabledQuerySubscriptionOptions<QueryResult, QueryVariables> = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datocms/svelte",
|
|
3
|
-
"version": "4.2.
|
|
3
|
+
"version": "4.2.4",
|
|
4
4
|
"description": "A set of components and utilities to work faster with DatoCMS in Svelte",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"@testing-library/svelte": "^4.1.0",
|
|
46
46
|
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
|
47
47
|
"@typescript-eslint/parser": "^5.62.0",
|
|
48
|
+
"@types/node": "^25.0.10",
|
|
48
49
|
"csstype": "^3.1.3",
|
|
49
50
|
"datocms-structured-text-generic-html-renderer": "^5.0.0",
|
|
50
51
|
"doctoc": "^2.0.0",
|
|
@@ -59,18 +60,24 @@
|
|
|
59
60
|
"svelte": "^4.0.0",
|
|
60
61
|
"svelte-check": "^3.6.2",
|
|
61
62
|
"tslib": "^2.6.2",
|
|
62
|
-
"typescript": "^5.
|
|
63
|
+
"typescript": "^5.9.3",
|
|
63
64
|
"vite": "^5.0.0",
|
|
64
65
|
"vitest": "^1.0.0"
|
|
65
66
|
},
|
|
66
67
|
"type": "module",
|
|
67
68
|
"dependencies": {
|
|
68
|
-
"datocms-
|
|
69
|
+
"@datocms/content-link": "^0.3.9",
|
|
70
|
+
"datocms-listen": "^1.0.2",
|
|
69
71
|
"datocms-structured-text-utils": "^5.1.6",
|
|
70
72
|
"svelte-intersection-observer": "^1.0.0"
|
|
71
73
|
},
|
|
72
74
|
"exports": {
|
|
73
75
|
"./package.json": "./package.json",
|
|
76
|
+
"./components/ContentLink/ContentLink.svelte": {
|
|
77
|
+
"types": "./package/components/ContentLink/ContentLink.svelte.d.ts",
|
|
78
|
+
"svelte": "./package/components/ContentLink/ContentLink.svelte",
|
|
79
|
+
"default": "./package/components/ContentLink/ContentLink.svelte"
|
|
80
|
+
},
|
|
74
81
|
"./components/Head/Head.svelte": {
|
|
75
82
|
"types": "./package/components/Head/Head.svelte.d.ts",
|
|
76
83
|
"svelte": "./package/components/Head/Head.svelte",
|
|
@@ -173,6 +180,9 @@
|
|
|
173
180
|
"svelte": "./package/index.js",
|
|
174
181
|
"typesVersions": {
|
|
175
182
|
">4.0": {
|
|
183
|
+
"components/ContentLink/ContentLink.svelte": [
|
|
184
|
+
"./package/components/ContentLink/ContentLink.svelte.d.ts"
|
|
185
|
+
],
|
|
176
186
|
"components/Head/Head.svelte": [
|
|
177
187
|
"./package/components/Head/Head.svelte.d.ts"
|
|
178
188
|
],
|