UNPKG

@v4fire/client

Version:

V4Fire client core library

174 lines (135 loc) 3.38 kB
/*! * V4Fire Client Core * https://github.com/V4Fire/Client * * Released under the MIT license * https://github.com/V4Fire/Client/blob/master/LICENSE */ import { $$ } from 'form/b-select/const'; import type bSelect from 'form/b-select/b-select'; import type { Items } from 'form/b-select/interface'; /** * Initializes component values * @param component */ export function initComponentValues<C extends bSelect>(component: C): void { const {unsafe} = component; const values = new Map(), indexes = {}; const valueStore = unsafe.field.get('valueStore'); let selectedItem; for (let i = 0; i < unsafe.items.length; i++) { const item = unsafe.items[i]; if (item.selected && (unsafe.multiple ? unsafe.valueProp === undefined : valueStore === undefined)) { unsafe.selectValue(item.value); } if (unsafe.isSelected(item.value)) { selectedItem = item; } values.set(item.value, i); indexes[i] = item; } unsafe.values = values; unsafe.indexes = indexes; if (!unsafe.multiple && selectedItem != null) { unsafe.field.set('textStore', selectedItem.label); } } /** * Normalizes the specified items and returns it * @param items */ export function normalizeItems(items: CanUndef<Items>): Items { const res = <Items>[]; if (items == null) { return res; } for (let i = 0; i < items.length; i++) { const item = items[i]; res.push({ ...item, value: item.value !== undefined ? item.value : item.label }); } return res; } /** * Sets the scroll position to the first marked or selected item */ export async function setScrollToMarkedOrSelectedItem<C extends bSelect>(component: C): Promise<boolean> { const {unsafe} = component; if (unsafe.native) { return false; } try { const dropdown = await unsafe.waitRef<HTMLDivElement>('dropdown', {label: $$.setScrollToSelectedItem}); const {block: $b} = unsafe; if ($b == null) { return false; } const itemEl = // @ts-ignore (TS 4.6.3) $b.element<HTMLDivElement>('item', {marked: true}) ?? $b.element<HTMLDivElement>('item', {selected: true}); if (itemEl == null) { return false; } let { clientHeight, scrollTop } = dropdown; let { offsetTop: itemOffsetTop, offsetHeight: itemOffsetHeight } = itemEl; itemOffsetHeight += parseFloat(getComputedStyle(itemEl).marginTop); if (itemOffsetTop > clientHeight + scrollTop) { while (itemOffsetTop > clientHeight + scrollTop) { scrollTop += itemOffsetHeight; } } else { while (itemOffsetTop < scrollTop) { scrollTop -= itemOffsetHeight; } } dropdown.scrollTop = scrollTop; } catch { return false; } return true; } /** * Returns a link to the selected item element. * If the component is switched to the `multiple` mode, the getter will return an array of elements. */ export function getSelectedElement<C extends bSelect>(component: C): CanPromise<CanUndef<CanArray<HTMLOptionElement>>> { const { value, unsafe } = component; const getEl = (value) => { const id = unsafe.values.get(value); if (id != null) { return unsafe.block?.element<HTMLOptionElement>('item', {id}); } }; return unsafe.waitStatus('ready', () => { if (unsafe.multiple) { if (!Object.isSet(value)) { return []; } return [...value].flatMap((val) => getEl(val) ?? []); } return getEl(value); }); }