Tidy up logic for showing and hiding popovers for bindings and helpers

This commit is contained in:
Andrew Kingston 2024-02-20 10:11:27 +00:00
parent 7a278234b5
commit ca3f464523
4 changed files with 91 additions and 74 deletions

View File

@ -117,7 +117,7 @@
const indentWithTabCustom = {
key: "Tab",
run: view => {
if (completionStatus(view.state) == "active") {
if (completionStatus(view.state) === "active") {
acceptCompletion(view)
return true
}
@ -131,7 +131,7 @@
}
const buildKeymap = () => {
const baseMap = [
return [
...closeBracketsKeymap,
...defaultKeymap,
...historyKeymap,
@ -139,7 +139,6 @@
...completionKeymap,
indentWithTabCustom,
]
return baseMap
}
const buildBaseExtensions = () => {
@ -215,7 +214,7 @@
)
}
if (mode.name == "javascript") {
if (mode.name === "javascript") {
complete.push(javascript())
complete.push(highlightWhitespace())
complete.push(lineNumbers())
@ -321,4 +320,19 @@
border-radius: var(--border-radius-s);
padding: 4px 6px;
}
.code-editor :global(.binding__example) {
padding: 0;
margin: 0;
font-size: 12px;
white-space: pre;
text-overflow: ellipsis;
overflow: hidden;
max-height: 480px;
}
.code-editor :global(.binding__example span) {
overflow: hidden !important;
text-overflow: ellipsis !important;
white-space: nowrap !important;
}
</style>

View File

@ -255,6 +255,11 @@ export const buildBindingInfoNode = (completion, binding) => {
const ele = document.createElement("div")
ele.classList.add("info-bubble")
if (binding.valueHTML) {
ele.innerHTML = `<div class="binding__example">${binding.valueHTML}</div>`
return ele
}
const exampleNodeHtml = binding.readableBinding
? `<div class="binding__example">{{ ${binding.readableBinding} }}</div>`
: ""

View File

@ -62,16 +62,45 @@
let targetMode = null
let expressionResult
$: enrichedBindings = enrichBindings(bindings, context)
$: usingJS = mode === "JavaScript"
$: editorMode =
mode === "JavaScript" ? EditorModes.JS : EditorModes.Handlebars
$: bindingCompletions = bindingsToCompletions(bindings, editorMode)
$: runtimeExpression = readableToRuntimeBinding(bindings, value)
$: bindingCompletions = bindingsToCompletions(enrichedBindings, editorMode)
$: runtimeExpression = readableToRuntimeBinding(enrichedBindings, value)
$: expressionResult = processStringSync(runtimeExpression || "", context)
$: bindingHelpers = new BindingHelpers(getCaretPosition, insertAtPos)
const getBindingValue = (binding, context) => {
const hbs = `{{ literal ${binding.runtimeBinding} }}`
const res = processStringSync(hbs, context)
return JSON.stringify(res, null, 2)
}
const highlightJSON = json => {
return formatHighlight(json, {
keyColor: "#e06c75",
numberColor: "#e5c07b",
stringColor: "#98c379",
trueColor: "#d19a66",
falseColor: "#d19a66",
nullColor: "#c678dd",
})
}
const enrichBindings = (bindings, context) => {
return bindings.map(binding => {
const value = getBindingValue(binding, context)
return {
...binding,
value,
valueHTML: highlightJSON(value),
}
})
}
const updateValue = val => {
const runtimeExpression = readableToRuntimeBinding(bindings, val)
const runtimeExpression = readableToRuntimeBinding(enrichedBindings, val)
valid = isValid(runtimeExpression)
if (valid) {
dispatch("change", val)
@ -116,9 +145,9 @@
}
const convert = () => {
const runtime = readableToRuntimeBinding(bindings, hbsValue)
const runtime = readableToRuntimeBinding(enrichedBindings, hbsValue)
const runtimeJs = encodeJSBinding(convertToJS(runtime))
jsValue = runtimeToReadableBinding(bindings, runtimeJs)
jsValue = runtimeToReadableBinding(enrichedBindings, runtimeJs)
hbsValue = null
mode = "JavaScript"
onSelectBinding("", { forceJS: true })
@ -143,7 +172,7 @@
}
onMount(() => {
valid = isValid(readableToRuntimeBinding(bindings, value))
valid = isValid(readableToRuntimeBinding(enrichedBindings, value))
})
</script>
@ -261,7 +290,7 @@
{#if sidebar}
<div class="binding-picker">
<BindingPicker
{bindings}
bindings={enrichedBindings}
{allowHelpers}
{context}
addHelper={onSelectHelper}
@ -348,7 +377,7 @@
{#if sidebar}
<div class="binding-picker">
<BindingPicker
{bindings}
bindings={enrichedBindings}
{allowHelpers}
{context}
addHelper={onSelectHelper}

View File

@ -71,36 +71,26 @@
return names
}
const getBindingValue = binding => {
const hbs = `{{ literal ${binding.runtimeBinding} }}`
const res = processStringSync(hbs, context)
return JSON.stringify(res, null, 2)
}
const highlight = json => {
return formatHighlight(json, {
keyColor: "#e06c75",
numberColor: "#e5c07b",
stringColor: "#98c379",
trueColor: "#d19a66",
falseColor: "#d19a66",
nullColor: "#c678dd",
})
}
const showPopover = (target, binding) => {
if (hideTimeout) {
clearTimeout(hideTimeout)
hideTimeout = null
}
let val = getBindingValue(binding)
if (val !== "") {
const showBindingPopover = (binding, target) => {
stopHidingPopover()
popoverAnchor = target
hoverTarget = {
code: val,
code: binding.valueHTML,
}
popover.show()
}
const showHelperPopover = (helper, target) => {
stopHidingPopover()
if (!helper.displayText && helper.description) {
return
}
popoverAnchor = target
hoverTarget = {
description: helper.description,
code: getHelperExample(helper, mode.name === "javascript"),
}
popover.show()
}
const hidePopover = () => {
@ -112,7 +102,7 @@
}, 100)
}
const stopHiding = () => {
const stopHidingPopover = () => {
if (hideTimeout) {
clearTimeout(hideTimeout)
hideTimeout = null
@ -126,9 +116,10 @@
anchor={popoverAnchor}
minWidth={0}
maxWidth={480}
maxHeight={300}
maxHeight={480}
dismissible={false}
on:mouseenter={stopHiding}
on:mouseenter={stopHidingPopover}
on:mouseleave={hidePopover}
>
<div class="helper">
<Layout gap="S">
@ -139,10 +130,8 @@
</div>
{/if}
{#if hoverTarget.code}
<pre>
<!-- eslint-disable-next-line svelte/no-at-html-tags-->
{@html highlight(hoverTarget.code)}
</pre>
<pre>{@html hoverTarget.code}</pre>
{/if}
</Layout>
</div>
@ -212,10 +201,8 @@
{#each category.bindings as binding}
<li
class="binding"
on:mouseenter={e => showPopover(e.target, binding)}
on:mouseenter={e => showBindingPopover(binding, e.target)}
on:mouseleave={hidePopover}
on:focus={() => {}}
on:blur={() => {}}
on:click={() => addBinding(binding)}
>
<span class="binding__label">
@ -227,7 +214,6 @@
{binding.readableBinding}
{/if}
</span>
{#if binding.display?.type || binding.fieldSchema?.type}
<span class="binding__typeWrap">
<span class="binding__type">
@ -250,26 +236,9 @@
{#each filteredHelpers as helper}
<li
class="binding"
on:mouseenter={e => showHelperPopover(helper, e.target)}
on:mouseleave={hidePopover}
on:click={() => addHelper(helper, mode.name === "javascript")}
on:mouseenter={e => {
popoverAnchor = e.target
if (!helper.displayText && helper.description) {
return
}
hoverTarget = {
description: helper.description,
code: getHelperExample(helper, mode.name === "javascript"),
}
popover.show()
e.stopPropagation()
}}
on:mouseleave={() => {
popover.hide()
popoverAnchor = null
hoverTarget = null
}}
on:focus={() => {}}
on:blur={() => {}}
>
<span class="binding__label">{helper.displayText}</span>
<span class="binding__typeWrap">
@ -287,16 +256,16 @@
<style>
.search :global(input) {
border: none;
border-radius: 0px;
border-radius: 0;
background: none;
padding: 0px;
padding: 0;
}
.search {
padding: var(--spacing-m) var(--spacing-l);
display: flex;
align-items: center;
border-top: 0px;
border-top: 0;
border-bottom: var(--border-light);
border-left: 2px solid transparent;
border-right: 2px solid transparent;
@ -316,17 +285,17 @@
}
ul.category-list {
padding: 0px var(--spacing-l);
padding: 0 var(--spacing-l);
padding-bottom: var(--spacing-l);
}
.sub-section {
padding: var(--spacing-l);
padding-top: 0px;
padding-top: 0;
}
.sub-section-back {
padding: var(--spacing-l);
padding-top: var(--spacing-xl);
padding-bottom: 0px;
padding-bottom: 0;
}
.cat-heading {
margin-bottom: var(--spacing-l);