@teamnovu/statamic-live-preview-nuxt
Advanced tools
Comparing version 1.1.0 to 1.3.0
@@ -5,4 +5,8 @@ # Changelog | ||
## [1.3.0](https://github.com/teamnovu/statamic-live-preview-nuxt/compare/v1.2.0...v1.3.0) (2022-05-23) | ||
## [1.2.0](https://github.com/teamnovu/statamic-live-preview-nuxt/compare/v1.1.0...v1.2.0) (2022-05-23) | ||
## [1.1.0](https://github.com/teamnovu/statamic-live-preview-nuxt/compare/v1.0.0...v1.1.0) (2022-04-27) | ||
## 1.0.0 (2022-04-20) |
@@ -0,1 +1,7 @@ | ||
/** | ||
* The identifier that will be used to | ||
* set the element's data attribute via the Vue directive | ||
*/ | ||
const targetIdentifier = 'editor-target' | ||
function log(...message) { | ||
@@ -9,3 +15,89 @@ console.log( | ||
module.exports = ({ app, query, $axios, $graphql, enablePreview }) => { | ||
/** | ||
* Scroll to the given element in the DOM | ||
*/ | ||
function scrollTo(element) { | ||
element.scrollIntoView({ | ||
behavior: "smooth", | ||
block: "center", | ||
inline: "nearest" | ||
}); | ||
} | ||
/** | ||
* Look for the closest ancestor with the target identifier | ||
* of the given element | ||
*/ | ||
function getParentIdentifierRecursively(element) { | ||
if (!element) return null | ||
const attrValue = element.getAttribute(`data-${targetIdentifier}`) | ||
if (!attrValue) { | ||
return getParentIdentifierRecursively(element.parentElement) | ||
} | ||
const ancestorIdentifier = getParentIdentifierRecursively(element.parentElement) | ||
if (!ancestorIdentifier) { | ||
return attrValue | ||
} | ||
return `${ancestorIdentifier}.${attrValue}` | ||
} | ||
/** | ||
* Find the closest ancestor that matches the given identifier | ||
*/ | ||
function findMatchingTargetRecursively(targets, elementIdentifier) { | ||
if (targets.length === 0) return null | ||
const matchingTarget = targets.find((target) => elementIdentifier === target.identifier) | ||
if (matchingTarget) { | ||
return matchingTarget | ||
} | ||
if (!elementIdentifier.includes('.')) { | ||
return null | ||
} | ||
return findMatchingTargetRecursively(targets, elementIdentifier.split('.').slice(0, -1).join('.')) | ||
} | ||
/** | ||
* Get the element that matches the given identifier | ||
* Ultimately, this will be the element that we want to scroll to | ||
*/ | ||
function getElement(elementIdentifier) { | ||
// get all nodes with the target identifier | ||
let targets = [...document.querySelectorAll(`[data-${targetIdentifier}]`)] | ||
targets = targets.map((target) => { | ||
let identifier = target.getAttribute(`data-${targetIdentifier}`) | ||
const ancestorIdentifier = getParentIdentifierRecursively(target.parentElement) | ||
// the target might be nested within another target | ||
// when that is the case, we need to concatenate the ancestor identifier with the element identifier | ||
if (ancestorIdentifier) { | ||
identifier = `${ancestorIdentifier}.${identifier}` | ||
} | ||
return { | ||
identifier, | ||
element: target | ||
} | ||
}) | ||
// filter out the ones that don't match the given identifier | ||
const matchingTarget = findMatchingTargetRecursively(targets, elementIdentifier) | ||
return matchingTarget?.element | ||
} | ||
/** | ||
* Listen for iframe post messages and handle them | ||
*/ | ||
export default ({ app, query, $axios, $graphql, enablePreview }) => { | ||
// Add token to new route query when changing route | ||
@@ -75,4 +167,13 @@ if (query.token) { | ||
// Add live preview update event handler | ||
window.onmessage = function (e) { | ||
if (e.data === 'live-preview-update') { | ||
window.onmessage = ({ data }) => { | ||
if (!data) return | ||
if (typeof data === 'object' && data.focusedElement) { | ||
const element = getElement(data.focusedElement) | ||
if (!element) return | ||
scrollTo(element) | ||
} else if (data === 'live-preview-update') { | ||
log('Refreshing page...') | ||
@@ -84,1 +185,16 @@ window.$nuxt?.refresh() | ||
} | ||
/** | ||
* Register Vue directive | ||
* This will be used to set the element's data attribute | ||
*/ | ||
export const Directive = { | ||
install(Vue) { | ||
Vue.directive(targetIdentifier, { | ||
bind: (el, { value }) => { | ||
// Set the element's data attribute | ||
el.setAttribute(`data-${targetIdentifier}`, value); | ||
}, | ||
}); | ||
} | ||
} |
{ | ||
"name": "@teamnovu/statamic-live-preview-nuxt", | ||
"version": "1.1.0", | ||
"version": "1.3.0", | ||
"description": "A Nuxt.js Plugin for the Statamic Live Preview", | ||
@@ -9,2 +9,4 @@ "private": false, | ||
"release": "standard-version && git push --follow-tags && npm publish", | ||
"release-minor": "standard-version --release-as minor && git push --follow-tags && npm publish", | ||
"release-major": "standard-version --release-as major && git push --follow-tags && npm publish", | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
@@ -11,0 +13,0 @@ }, |
@@ -42,2 +42,46 @@ # Statamic Live Preview for Nuxt | ||
### ScrollTo Element Behavior (Optional) | ||
Register the Vue Directive to enable ScrollTo Element behavior. | ||
```javascript | ||
import Vue from 'vue' | ||
import livePreview, { Directive } from '@teamnovu/statamic-live-preview-nuxt' | ||
Vue.use(Directive) | ||
export default livePreview | ||
``` | ||
Use it like this: | ||
```html | ||
<h2 v-editor-target="'title'">This is a headline</h2> | ||
``` | ||
Nested Example: | ||
```html | ||
<!-- pages/_.vue --> | ||
<ComponentsLoader | ||
:components="page.replicator_product_components" | ||
v-editor-target="'replicator_product_components'" | ||
/> | ||
``` | ||
All values used with `v-editor-target` must match the corresponding field `handle` of the CMS. | ||
Then within your ComponentsLoader.vue: | ||
```html | ||
<!-- components/ComponentsLoader.vue --> | ||
<Component | ||
... | ||
v-editor-target="index" | ||
/> | ||
``` | ||
If you nest `v-editor-target` their values will be concatenated. For Example: `replicator_product_components.0.title`. | ||
### Transpilation | ||
@@ -44,0 +88,0 @@ |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
8661
161
98
4
1