UNPKG

uicore-ts

Version:

UICore is a library to build native-like user interfaces using pure Typescript. No HTML is needed at all. Components are described as TS classes and all user interactions are handled explicitly. This library is strongly inspired by the UIKit framework tha

286 lines (285 loc) 10.4 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var UIAutocompleteTextField_exports = {}; __export(UIAutocompleteTextField_exports, { UIAutocompleteTextField: () => UIAutocompleteTextField }); module.exports = __toCommonJS(UIAutocompleteTextField_exports); var import_UIAutocompleteDropdownView = require("./UIAutocompleteDropdownView"); var import_UIObject = require("./UIObject"); var import_UITextField = require("./UITextField"); var import_UIView = require("./UIView"); const _UIAutocompleteTextField = class extends import_UITextField.UITextField { constructor(elementID) { super(elementID); this._autocompleteItems = []; this._isDropdownOpen = import_UIObject.NO; this._strictSelection = import_UIObject.NO; this._isValid = import_UIObject.YES; this._userHasNavigatedDropdown = import_UIObject.NO; this.usesMultiWordAndSearch = import_UIObject.NO; this._dropdownView = this.newDropdownView(); this._dropdownView.didSelectItem = (item) => { this.commitSelection(item); }; let textBeforeFocus = this.text; let itemBeforeFocus = this.selectedItem; this.controlEventTargetAccumulator.Focus = () => { textBeforeFocus = this.text; itemBeforeFocus = this.selectedItem; this._userHasNavigatedDropdown = import_UIObject.NO; this.openDropdown(); this.textElementView.viewHTMLElement.select(); const matchIndex = this._dropdownView.filteredItems.findIndex( (item) => item.label === textBeforeFocus ); if (matchIndex !== -1) { this._dropdownView.highlightedRowIndex = matchIndex; } }; this.controlEventTargetAccumulator.Blur = () => { this.closeDropdown(); }; this.addTargetForControlEvent(import_UITextField.UITextField.controlEvent.TextChange, () => { this._selectedItem = void 0; this._userHasNavigatedDropdown = this.text.length > 0; this.updateFilteredItems(); if (!this._isDropdownOpen) { this.openDropdown(); } }); this.textElementView.addTargetForControlEvent(import_UIView.UIView.controlEvent.DownArrowDown, (sender, event) => { event.preventDefault(); if (!this._isDropdownOpen) { this.openDropdown(); return; } this._userHasNavigatedDropdown = import_UIObject.YES; const maxIndex = this._dropdownView.filteredItems.length - 1; if (this._dropdownView.highlightedRowIndex < maxIndex) { this._dropdownView.highlightedRowIndex = this._dropdownView.highlightedRowIndex + 1; } }); this.textElementView.addTargetForControlEvent(import_UIView.UIView.controlEvent.UpArrowDown, (sender, event) => { event.preventDefault(); this._userHasNavigatedDropdown = import_UIObject.YES; if (this._dropdownView.highlightedRowIndex > 0) { this._dropdownView.highlightedRowIndex = this._dropdownView.highlightedRowIndex - 1; } }); this.addTargetForControlEvent(import_UIView.UIView.controlEvent.EnterDown, () => { const highlightedItem = this._dropdownView.highlightedItem; if ((0, import_UIObject.IS)(highlightedItem)) { this.commitSelection(highlightedItem); } else if (this._isDropdownOpen) { this.closeDropdown(); } }); this.addTargetForControlEvent(import_UIView.UIView.controlEvent.TabDown, (sender, event) => { if (this._isDropdownOpen && this._userHasNavigatedDropdown) { const highlightedItem = this._dropdownView.highlightedItem; if ((0, import_UIObject.IS)(highlightedItem)) { event.preventDefault(); this.commitSelection(highlightedItem); } } }); this.addTargetForControlEvent(import_UIView.UIView.controlEvent.EscDown, () => { if (this._isDropdownOpen) { this.closeDropdown(); if (this.strictSelection) { this.commitSelection(itemBeforeFocus); } else { this.text = textBeforeFocus; } } }); } get controlEventTargetAccumulator() { return super.controlEventTargetAccumulator; } newDropdownView() { return new import_UIAutocompleteDropdownView.UIAutocompleteDropdownView( this.elementID ? this.elementID + "Dropdown" : void 0 ); } get selectedItem() { var _a; return (_a = this._selectedItem) == null ? void 0 : _a.value; } get strictSelection() { return this._strictSelection; } set strictSelection(strict) { this._strictSelection = strict; this.updateValidationVisuals(); } commitSelection(item) { this._selectedItem = item; this.text = item.label; this.closeDropdown(); this.updateValidationVisuals(); this.sendControlEventForKey(_UIAutocompleteTextField.controlEvent.SelectionDidChange); } set autocompleteStrings(strings) { this._autocompleteItems = strings.map((s) => ({ label: s, value: s })); this.updateFilteredItems(); } get autocompleteStrings() { return this._autocompleteItems.map((item) => item.label); } set autocompleteData(items) { this._autocompleteItems = items; this.updateFilteredItems(); } get autocompleteData() { return this._autocompleteItems; } _filterWordsFromText(filterText) { if (filterText.length === 0) { return []; } if (this.usesMultiWordAndSearch) { return filterText.split(/\s+/).filter((word) => word.length > 0); } return [filterText]; } _labelMatchesFilterWords(label, filterWords) { return filterWords.every((word) => label.includes(word)); } _isWordBoundary(label, position) { if (position === 0) { return import_UIObject.YES; } const charBefore = label[position - 1]; return " -/\\|._,;:()[]".includes(charBefore); } _scoreLabel(label, filterWords) { if (filterWords.length === 0) { return label.length; } let cursor = 0; let isSequential = import_UIObject.YES; const sequentialPositions = []; for (const word of filterWords) { const position = label.indexOf(word, cursor); if (position === -1) { isSequential = import_UIObject.NO; break; } sequentialPositions.push(position); cursor = position + word.length; } let boundaryScore = 0; for (const word of filterWords) { const position = label.indexOf(word); if (position !== -1 && !this._isWordBoundary(label, position)) { boundaryScore += 1; } } const firstMatchPosition = label.indexOf(filterWords[0]); const sequentialPenalty = isSequential ? 0 : 1e7; return sequentialPenalty + boundaryScore * 1e4 + firstMatchPosition * 100 + label.length; } updateFilteredItems() { const rawFilterText = this.text.toLowerCase().trim(); const filterWords = this._filterWordsFromText(rawFilterText); let filtered; if (filterWords.length === 0) { filtered = this._autocompleteItems; } else { filtered = this._autocompleteItems.filter((item) => this._labelMatchesFilterWords(item.label.toLowerCase(), filterWords)).map((item, originalIndex) => ({ item, originalIndex, score: this._scoreLabel(item.label.toLowerCase(), filterWords) })).sort((a, b) => a.score - b.score || a.originalIndex - b.originalIndex).map(({ item }) => item); } const isExactSingleMatch = filtered.length === 1 && filtered[0].label.toLowerCase() === rawFilterText; this._dropdownView.filterWords = filterWords; this._dropdownView.filteredItems = isExactSingleMatch ? [] : filtered; if (this._dropdownView.filteredItems.length > 0) { this._dropdownView.highlightedRowIndex = 0; } if (this._isDropdownOpen) { this._dropdownView.showAnchoredToView(this); } } openDropdown() { if (this._isDropdownOpen) { return; } this._isDropdownOpen = import_UIObject.YES; this._dropdownView.filterWords = []; this.updateFilteredItems(); this._dropdownView.showAnchoredToView(this); } closeDropdown() { if (!this._isDropdownOpen) { return; } this._isDropdownOpen = import_UIObject.NO; this._dropdownView.dismiss(); if (this._strictSelection && (0, import_UIObject.IS_NOT)(this._selectedItem)) { const currentText = this.text.trim(); if (currentText.length > 0) { const matchingItem = this._autocompleteItems.find( (item) => item.label === currentText ); if ((0, import_UIObject.IS)(matchingItem)) { this._selectedItem = matchingItem; } else { this.text = ""; this._selectedItem = void 0; this.sendControlEventForKey(import_UITextField.UITextField.controlEvent.TextChange); } } } this.updateValidationVisuals(); } get isValid() { if (!this._strictSelection) { return import_UIObject.YES; } const currentText = this.text.trim(); if (currentText.length === 0) { return import_UIObject.YES; } return this._autocompleteItems.some((item) => item.label === currentText); } updateValidationVisuals() { } wasRemovedFromViewTree() { super.wasRemovedFromViewTree(); this._dropdownView.removeFromSuperview(); } layoutSubviews() { super.layoutSubviews(); if (this._isDropdownOpen) { this._dropdownView.showAnchoredToView(this); } } }; let UIAutocompleteTextField = _UIAutocompleteTextField; UIAutocompleteTextField.controlEvent = Object.assign({}, import_UITextField.UITextField.controlEvent, { "SelectionDidChange": "SelectionDidChange" }); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { UIAutocompleteTextField }); //# sourceMappingURL=UIAutocompleteTextField.js.map