aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/MenuItem.mjs41
-rw-r--r--src/css/index.css5
-rw-r--r--src/editor.mjs22
3 files changed, 31 insertions, 37 deletions
diff --git a/src/MenuItem.mjs b/src/MenuItem.mjs
index d485032..4028702 100644
--- a/src/MenuItem.mjs
+++ b/src/MenuItem.mjs
@@ -134,41 +134,32 @@ export const addGeoLink = ({ utils }, range) =>
134 } 134 }
135 }) 135 })
136 136
137export class Suggestion { 137export class Suggestion extends Item {
138 constructor ({ text, replace }) { 138 constructor ({ text, replace, cm }) {
139 this.text = text 139 super({ text })
140 this.replace = replace 140 this.replace = replace
141 } 141 this.classList.add('suggestion')
142 142
143 createElement (codemirror) { 143 this.onmouseover = () => {
144 const option = document.createElement('div') 144 Array.from(this.parentElement?.children)?.forEach(s =>
145 if (this.text.startsWith('<')) {
146 option.innerHTML = this.text
147 } else {
148 option.innerText = this.text
149 }
150 option.classList.add('container__suggestion')
151 option.onmouseover = () => {
152 Array.from(option.parentElement?.children)?.forEach(s =>
153 s.classList.remove('focus') 145 s.classList.remove('focus')
154 ) 146 )
155 option.classList.add('focus') 147 this.classList.add('focus')
156 } 148 }
157 option.onmouseout = () => { 149 this.onmouseout = () => {
158 option.classList.remove('focus') 150 this.classList.remove('focus')
159 } 151 }
160 option.onclick = () => { 152 this.onclick = () => {
161 const anchor = codemirror.getCursor() 153 const anchor = cm.getCursor()
162 codemirror.setSelection(anchor, { ...anchor, ch: 0 }) 154 cm.setSelection(anchor, { ...anchor, ch: 0 })
163 codemirror.replaceSelection(this.replace) 155 cm.replaceSelection(this.replace)
164 codemirror.focus() 156 cm.focus()
165 const newAnchor = { ...anchor, ch: this.replace.length } 157 const newAnchor = { ...anchor, ch: this.replace.length }
166 codemirror.setCursor(newAnchor) 158 cm.setCursor(newAnchor)
167 } 159 }
168
169 return option
170 } 160 }
171} 161}
162window.customElements.define('menu-item-suggestion', Suggestion, { extends: 'div' })
172 163
173export const renderResults = ({ modal, modalContent }, map) => 164export const renderResults = ({ modal, modalContent }, map) =>
174 new Item({ 165 new Item({
diff --git a/src/css/index.css b/src/css/index.css
index 858182d..a2ef454 100644
--- a/src/css/index.css
+++ b/src/css/index.css
@@ -117,13 +117,12 @@ body {
117 } 117 }
118} 118}
119 119
120.container__suggestion { 120.suggestion {
121 display: flex; 121 display: flex;
122 overflow: hidden; 122 overflow: hidden;
123 justify-content: space-between; 123 justify-content: space-between;
124 align-items: center; 124 align-items: center;
125 height: fit-content; 125 max-width: 700px;
126 min-height: 2rem;
127 126
128 cursor: pointer; 127 cursor: pointer;
129 white-space: nowrap; 128 white-space: nowrap;
diff --git a/src/editor.mjs b/src/editor.mjs
index 2938745..82d93b0 100644
--- a/src/editor.mjs
+++ b/src/editor.mjs
@@ -3,6 +3,7 @@
3import { markdown2HTML, generateMaps } from './dumbymap' 3import { markdown2HTML, generateMaps } from './dumbymap'
4import { defaultAliases, parseConfigsFromYaml } from 'mapclay' 4import { defaultAliases, parseConfigsFromYaml } from 'mapclay'
5import * as menuItem from './MenuItem' 5import * as menuItem from './MenuItem'
6import { shiftByWindow } from './utils.mjs'
6 7
7// Set up Containers {{{ 8// Set up Containers {{{
8 9
@@ -382,7 +383,8 @@ const getSuggestionsForOptions = (optionTyped, validOptions) => {
382 o => 383 o =>
383 new menuItem.Suggestion({ 384 new menuItem.Suggestion({
384 text: `<span>${o.valueOf()}</span><span class='info' title="${o.desc ?? ''}">ⓘ</span>`, 385 text: `<span>${o.valueOf()}</span><span class='info' title="${o.desc ?? ''}">ⓘ</span>`,
385 replace: `${o.valueOf()}: ` 386 replace: `${o.valueOf()}: `,
387 cm
386 }) 388 })
387 ) 389 )
388} 390}
@@ -397,7 +399,8 @@ const getSuggestionFromMapOption = option => {
397 399
398 return new menuItem.Suggestion({ 400 return new menuItem.Suggestion({
399 text, 401 text,
400 replace: `${option.valueOf()}: ${option.example ?? ''}` 402 replace: `${option.valueOf()}: ${option.example ?? ''}`,
403 cm
401 }) 404 })
402} 405}
403// }}} 406// }}}
@@ -408,7 +411,8 @@ const getSuggestionsFromAliases = option =>
408 const valueString = JSON.stringify(value).replaceAll('"', '') 411 const valueString = JSON.stringify(value).replaceAll('"', '')
409 return new menuItem.Suggestion({ 412 return new menuItem.Suggestion({
410 text: `<span>${alias}</span><span class="truncate" style="color: gray">${valueString}</span>`, 413 text: `<span>${alias}</span><span class="truncate" style="color: gray">${valueString}</span>`,
411 replace: `${option.valueOf()}: ${valueString}` 414 replace: `${option.valueOf()}: ${valueString}`,
415 cm
412 }) 416 })
413 }) ?? [] 417 }) ?? []
414// }}} 418// }}}
@@ -523,7 +527,8 @@ const getSuggestions = anchor => {
523 ([renderer, info]) => 527 ([renderer, info]) =>
524 new menuItem.Suggestion({ 528 new menuItem.Suggestion({
525 text: `<span>use: ${renderer}</span><span class='info' title="${info.desc}">ⓘ</span>`, 529 text: `<span>use: ${renderer}</span><span class='info' title="${info.desc}">ⓘ</span>`,
526 replace: `use: ${renderer}` 530 replace: `use: ${renderer}`,
531 cm
527 }) 532 })
528 ) 533 )
529 return rendererSuggestions.length > 0 ? rendererSuggestions : [] 534 return rendererSuggestions.length > 0 ? rendererSuggestions : []
@@ -542,7 +547,6 @@ const addSuggestions = (anchor, suggestions) => {
542 547
543 menu.innerHTML = '' 548 menu.innerHTML = ''
544 suggestions 549 suggestions
545 .map(s => s.createElement(cm))
546 .forEach(option => menu.appendChild(option)) 550 .forEach(option => menu.appendChild(option))
547 551
548 const widgetAnchor = document.createElement('div') 552 const widgetAnchor = document.createElement('div')
@@ -550,8 +554,8 @@ const addSuggestions = (anchor, suggestions) => {
550 const rect = widgetAnchor.getBoundingClientRect() 554 const rect = widgetAnchor.getBoundingClientRect()
551 menu.style.left = `calc(${rect.left}px + 2rem)` 555 menu.style.left = `calc(${rect.left}px + 2rem)`
552 menu.style.top = `calc(${rect.bottom}px + 1rem)` 556 menu.style.top = `calc(${rect.bottom}px + 1rem)`
553 menu.style.maxWidth = `calc(${window.innerWidth}px - ${rect.x}px - 3rem)`
554 menu.style.display = 'block' 557 menu.style.display = 'block'
558 shiftByWindow(menu)
555} 559}
556// }}} 560// }}}
557// EVENT: Suggests for current selection {{{ 561// EVENT: Suggests for current selection {{{
@@ -583,7 +587,7 @@ cm.on('keydown', (_, e) => {
583 ) { return } 587 ) { return }
584 588
585 // Directly add a newline when no suggestion is selected 589 // Directly add a newline when no suggestion is selected
586 const currentSuggestion = menu.querySelector('.container__suggestion.focus') 590 const currentSuggestion = menu.querySelector('.menu-item.focus')
587 if (!currentSuggestion && e.key === 'Enter') return 591 if (!currentSuggestion && e.key === 'Enter') return
588 592
589 // Override default behavior 593 // Override default behavior
@@ -592,10 +596,10 @@ cm.on('keydown', (_, e) => {
592 // Suggestion when pressing Tab or Shift + Tab 596 // Suggestion when pressing Tab or Shift + Tab
593 const nextSuggestion = 597 const nextSuggestion =
594 currentSuggestion?.nextSibling ?? 598 currentSuggestion?.nextSibling ??
595 menu.querySelector('.container__suggestion:first-child') 599 menu.querySelector('.menu-item:first-child')
596 const previousSuggestion = 600 const previousSuggestion =
597 currentSuggestion?.previousSibling ?? 601 currentSuggestion?.previousSibling ??
598 menu.querySelector('.container__suggestion:last-child') 602 menu.querySelector('.menu-item:last-child')
599 const focusSuggestion = e.shiftKey ? previousSuggestion : nextSuggestion 603 const focusSuggestion = e.shiftKey ? previousSuggestion : nextSuggestion
600 604
601 // Current editor selection state 605 // Current editor selection state