2021-01-06 11:13:30 +01:00
|
|
|
import { get } from "svelte/store"
|
|
|
|
import { builderStore } from "../store"
|
|
|
|
|
2020-11-24 10:31:54 +01:00
|
|
|
/**
|
2021-01-06 11:13:30 +01:00
|
|
|
* Helper to build a CSS string from a style object.
|
2020-11-24 10:31:54 +01:00
|
|
|
*/
|
2021-01-06 11:13:30 +01:00
|
|
|
const buildStyleString = (styleObject, customStyles) => {
|
2020-11-17 13:08:24 +01:00
|
|
|
let str = ""
|
2021-01-26 15:40:44 +01:00
|
|
|
Object.entries(styleObject || {}).forEach(([style, value]) => {
|
2020-11-24 10:31:54 +01:00
|
|
|
if (style && value != null) {
|
2020-11-17 13:08:24 +01:00
|
|
|
str += `${style}: ${value}; `
|
|
|
|
}
|
|
|
|
})
|
2021-01-06 11:13:30 +01:00
|
|
|
return str + (customStyles || "")
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Applies styles to enrich the builder preview.
|
|
|
|
* Applies styles to highlight the selected component, and allows pointer
|
|
|
|
* events for any selectable components (overriding the blanket ban on pointer
|
|
|
|
* events in the iframe HTML).
|
|
|
|
*/
|
2021-01-27 16:52:12 +01:00
|
|
|
const addBuilderPreviewStyles = (node, styleString, componentId) => {
|
|
|
|
if (componentId === get(builderStore).selectedComponentId) {
|
|
|
|
const style = window.getComputedStyle(node)
|
|
|
|
const property = style?.display === "table-row" ? "outline" : "border"
|
2021-04-29 10:41:49 +02:00
|
|
|
return (
|
|
|
|
styleString +
|
|
|
|
`;${property}: 2px solid #4285f4 !important; border-radius: 4px !important;`
|
|
|
|
)
|
2021-01-27 16:52:12 +01:00
|
|
|
} else {
|
|
|
|
return styleString
|
2021-01-04 19:39:17 +01:00
|
|
|
}
|
2020-11-17 13:08:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Svelte action to apply correct component styles.
|
2021-01-06 11:13:30 +01:00
|
|
|
* This also applies handlers for selecting components from the builder preview.
|
2020-11-17 13:08:24 +01:00
|
|
|
*/
|
|
|
|
export const styleable = (node, styles = {}) => {
|
2020-11-24 10:31:54 +01:00
|
|
|
let applyNormalStyles
|
|
|
|
let applyHoverStyles
|
2021-01-06 11:13:30 +01:00
|
|
|
let selectComponent
|
|
|
|
|
2020-11-24 10:31:54 +01:00
|
|
|
// Creates event listeners and applies initial styles
|
2021-01-26 15:40:44 +01:00
|
|
|
const setupStyles = (newStyles = {}) => {
|
2021-01-06 11:13:30 +01:00
|
|
|
const componentId = newStyles.id
|
2021-01-26 15:40:44 +01:00
|
|
|
const customStyles = newStyles.custom || ""
|
|
|
|
const normalStyles = newStyles.normal || {}
|
2020-11-24 10:31:54 +01:00
|
|
|
const hoverStyles = {
|
|
|
|
...normalStyles,
|
2021-01-26 15:40:44 +01:00
|
|
|
...(newStyles.hover || {}),
|
2020-11-24 10:31:54 +01:00
|
|
|
}
|
2020-11-17 13:08:24 +01:00
|
|
|
|
2021-01-27 16:52:12 +01:00
|
|
|
// Applies a style string to a DOM node
|
2021-05-03 09:31:09 +02:00
|
|
|
const applyStyles = (styleString) => {
|
2021-01-27 16:52:12 +01:00
|
|
|
node.style = addBuilderPreviewStyles(node, styleString, componentId)
|
2021-01-27 11:59:05 +01:00
|
|
|
node.dataset.componentId = componentId
|
2021-01-06 11:13:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Applies the "normal" style definition
|
2020-11-24 10:31:54 +01:00
|
|
|
applyNormalStyles = () => {
|
2021-01-06 11:13:30 +01:00
|
|
|
applyStyles(buildStyleString(normalStyles, customStyles))
|
2020-11-24 10:31:54 +01:00
|
|
|
}
|
2020-11-17 13:08:24 +01:00
|
|
|
|
2021-01-06 11:13:30 +01:00
|
|
|
// Applies any "hover" styles as well as the base "normal" styles
|
2020-11-24 10:31:54 +01:00
|
|
|
applyHoverStyles = () => {
|
2021-01-06 11:13:30 +01:00
|
|
|
applyStyles(buildStyleString(hoverStyles, customStyles))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handler to select a component in the builder when clicking it in the
|
|
|
|
// builder preview
|
2021-05-03 09:31:09 +02:00
|
|
|
selectComponent = (event) => {
|
2021-01-26 15:40:44 +01:00
|
|
|
builderStore.actions.selectComponent(componentId)
|
2021-01-27 16:52:12 +01:00
|
|
|
event.preventDefault()
|
|
|
|
event.stopPropagation()
|
|
|
|
return false
|
2020-11-24 10:31:54 +01:00
|
|
|
}
|
2020-11-17 13:08:24 +01:00
|
|
|
|
2020-11-24 10:31:54 +01:00
|
|
|
// Add listeners to toggle hover styles
|
|
|
|
node.addEventListener("mouseover", applyHoverStyles)
|
|
|
|
node.addEventListener("mouseout", applyNormalStyles)
|
2020-11-17 13:08:24 +01:00
|
|
|
|
2021-01-06 11:13:30 +01:00
|
|
|
// Add builder preview click listener
|
|
|
|
if (get(builderStore).inBuilder) {
|
|
|
|
node.addEventListener("click", selectComponent, false)
|
|
|
|
}
|
|
|
|
|
2020-11-24 10:31:54 +01:00
|
|
|
// Apply initial normal styles
|
|
|
|
applyNormalStyles()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Removes the current event listeners
|
|
|
|
const removeListeners = () => {
|
|
|
|
node.removeEventListener("mouseover", applyHoverStyles)
|
|
|
|
node.removeEventListener("mouseout", applyNormalStyles)
|
2021-01-06 11:13:30 +01:00
|
|
|
|
|
|
|
// Remove builder preview click listener
|
|
|
|
if (get(builderStore).inBuilder) {
|
|
|
|
node.removeEventListener("click", selectComponent)
|
|
|
|
}
|
2020-11-24 10:31:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Apply initial styles
|
|
|
|
setupStyles(styles)
|
2020-11-17 13:08:24 +01:00
|
|
|
|
|
|
|
return {
|
2020-11-24 10:31:54 +01:00
|
|
|
// Clean up old listeners and apply new ones on update
|
2021-05-03 09:31:09 +02:00
|
|
|
update: (newStyles) => {
|
2020-11-24 10:31:54 +01:00
|
|
|
removeListeners()
|
|
|
|
setupStyles(newStyles)
|
|
|
|
},
|
|
|
|
// Clean up listeners when component is destroyed
|
2020-11-17 13:08:24 +01:00
|
|
|
destroy: () => {
|
2020-11-24 10:31:54 +01:00
|
|
|
removeListeners()
|
2020-11-17 13:08:24 +01:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|