From 57a902834b6f48dcb068d0d8d53394c77273ec77 Mon Sep 17 00:00:00 2001 From: Kevin Chappell Date: Tue, 19 Nov 2024 14:40:33 -0800 Subject: [PATCH] fix: conditions component autocomplete visibility --- src/demo/js/options/index.js | 1 + src/lib/js/components/autocomplete.mjs | 61 +++++++++++++++++------- src/lib/js/config.js | 1 + src/lib/js/editor.js | 10 ++-- src/lib/sass/components/_field-edit.scss | 4 -- src/lib/sass/components/_panels.scss | 4 -- 6 files changed, 52 insertions(+), 29 deletions(-) diff --git a/src/demo/js/options/index.js b/src/demo/js/options/index.js index 00226875..4bf86d85 100644 --- a/src/demo/js/options/index.js +++ b/src/demo/js/options/index.js @@ -27,6 +27,7 @@ export const editorOptions = { sessionStorage: true, editPanelOrder: ['attrs', 'options'], // controlOnLeft: true, + // onLoad: () => {}, } export const renderOptions = { diff --git a/src/lib/js/components/autocomplete.mjs b/src/lib/js/components/autocomplete.mjs index 6e149814..6a613894 100644 --- a/src/lib/js/components/autocomplete.mjs +++ b/src/lib/js/components/autocomplete.mjs @@ -93,6 +93,12 @@ export const componentOptions = selectedId => { * Output an autocomplete form element */ export default class Autocomplete { + /** + * Create an Autocomplete instance + * @param {String} key - The key for the autocomplete instance + * @param {String} value - The initial value for the autocomplete input + * @param {String} i18nKey - The internationalization key for the autocomplete + */ constructor(key, value, i18nKey) { this.key = key this.className = key.replace(/\./g, '-') @@ -220,16 +226,16 @@ export default class Autocomplete { }) this.dom = dom.create({ - children: [this.displayField, this.hiddenField, this.list], + children: [this.displayField, this.hiddenField], className: this.className, action: { - onRender: () => { + onRender: element => { + this.stage = element.closest('.formeo-stage') const component = this.value && Components.getAddress(this.value) this.label = component && getComponentLabel(component) if (this.label) { this.displayField.value = this.label } - this.updateOptions() }, }, }) @@ -238,16 +244,17 @@ export default class Autocomplete { } updateOptions() { + let options = optionsCache const now = Date.now() - if (now - lastCache > ANIMATION_SPEED_SLOW) { + + if (!options || now - lastCache > ANIMATION_SPEED_SLOW * 10) { dom.empty(this.list) - this.generateOptions() + options = this.generateOptions() lastCache = now } - const options = optionsCache || this.generateOptions() - for (const option of options) { - this.list.appendChild(option) + if (!this.list.children.length) { + this.list.append(...options) } } @@ -291,13 +298,17 @@ export default class Autocomplete { return optionsCache } - /** - * Hides autocomplete list and deselects all the options - * @param {Object} list - list of autocomplete options - */ - hideList(list = this.list) { - animate.slideUp(list, ANIMATION_SPEED_FAST) - this.removeHighlight() + setListPosition() { + const { offsetHeight, offsetWidth } = this.displayField + const containerRect = this.displayField.closest('.formeo-stage').getBoundingClientRect() + const triggerRect = this.displayField.getBoundingClientRect() + const listStyle = { + position: 'absolute', + top: `${triggerRect.y + offsetHeight + window.scrollY - containerRect.y}px`, + left: `${triggerRect.x + window.scrollX - containerRect.x}px`, + width: `${offsetWidth + 1}px`, + } + Object.assign(this.list.style, listStyle) } /** @@ -306,18 +317,34 @@ export default class Autocomplete { * @param {Object} selectedOption - option to be selected */ showList(selectedOption, list = this.list) { + if (!this.stage.contains(this.list)) { + this.stage.appendChild(this.list) + } + this.setListPosition() this.selectOption(selectedOption) animate.slideDown(list, ANIMATION_SPEED_FAST) } + /** + * Hides autocomplete list and deselects all the options + * @param {Object} list - list of autocomplete options + */ + hideList(list = this.list) { + animate.slideUp(list, ANIMATION_SPEED_FAST) + this.removeHighlight() + if (this.stage.contains(this.list)) { + this.stage.removeChild(this.list) + } + } + /** * Returns first option from autocomplete list with 'active-option' class * @param {Object} list - list of autocomplete options * @return {Object} first list option with 'active-option' class */ getActiveOption(list = this.list) { - const activeOption = list.getElementsByClassName('active-option')[0] - if (activeOption && activeOption.style.display !== 'none') { + const activeOption = list.querySelector('.active-option') + if (activeOption?.style.display !== 'none') { return activeOption } return null diff --git a/src/lib/js/config.js b/src/lib/js/config.js index cdb2af4b..a18477de 100644 --- a/src/lib/js/config.js +++ b/src/lib/js/config.js @@ -26,6 +26,7 @@ export const defaults = { i18n: { location: 'https://draggable.github.io/formeo/assets/lang/', }, + onLoad: () => {}, } }, } diff --git a/src/lib/js/editor.js b/src/lib/js/editor.js index 7c50eb1a..fc55be06 100644 --- a/src/lib/js/editor.js +++ b/src/lib/js/editor.js @@ -73,12 +73,14 @@ export class FormeoEditor { promises.push(i18n.init({ ...this.opts.i18n, locale: window.sessionStorage?.getItem(SESSION_LOCALE_KEY) })) - const resolvedPromises = await Promise.all(promises) - if (this.opts.allowEdit) { - this.init() + promises.push(this.init()) } + const resolvedPromises = await Promise.all(promises) + + this.opts.onLoad?.(this) + return resolvedPromises } @@ -88,7 +90,7 @@ export class FormeoEditor { * dom elements, actions events and more. */ init() { - Controls.init(this.opts.controls, this.opts.stickyControls).then(controls => { + return Controls.init(this.opts.controls, this.opts.stickyControls).then(controls => { this.controls = controls this.load(this.userFormData, this.opts) this.formId = Components.get('id') diff --git a/src/lib/sass/components/_field-edit.scss b/src/lib/sass/components/_field-edit.scss index e645401b..544ff25d 100644 --- a/src/lib/sass/components/_field-edit.scss +++ b/src/lib/sass/components/_field-edit.scss @@ -27,10 +27,6 @@ list-style: decimal; } - .active-panel { - background-color: color.$white; - } - .field-prop { display: flex; } diff --git a/src/lib/sass/components/_panels.scss b/src/lib/sass/components/_panels.scss index 6915f61b..8358247b 100644 --- a/src/lib/sass/components/_panels.scss +++ b/src/lib/sass/components/_panels.scss @@ -101,10 +101,6 @@ } } - .f-panel { - background-color: color.$white; - } - .panel-labels { div { flex-direction: row;