uicore-ts 1.1.259 → 1.1.262
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compiledScripts/UIAutocompleteTextField.d.ts +1 -1
- package/compiledScripts/UIAutocompleteTextField.js +4 -13
- package/compiledScripts/UIAutocompleteTextField.js.map +2 -2
- package/compiledScripts/UIBaseButton.d.ts +52 -0
- package/compiledScripts/UIBaseButton.js +18 -3
- package/compiledScripts/UIBaseButton.js.map +2 -2
- package/compiledScripts/UIDateTimeInput.d.ts +1 -0
- package/compiledScripts/UITextField.d.ts +1 -0
- package/compiledScripts/UIView.d.ts +2 -0
- package/compiledScripts/UIView.js +9 -8
- package/compiledScripts/UIView.js.map +2 -2
- package/package.json +1 -1
- package/scripts/UIAutocompleteTextField.ts +7 -16
- package/scripts/UIBaseButton.ts +23 -2
- package/scripts/UIView.ts +11 -7
|
@@ -10,7 +10,6 @@ export declare class UIAutocompleteTextField<T = string> extends UITextField {
|
|
|
10
10
|
_strictSelection: boolean;
|
|
11
11
|
_isValid: boolean;
|
|
12
12
|
_userHasNavigatedDropdown: boolean;
|
|
13
|
-
_isProgrammaticTextChange: boolean;
|
|
14
13
|
/**
|
|
15
14
|
* When YES, the filter text is split on whitespace and all words must appear
|
|
16
15
|
* in the item label (AND logic). When NO (default), the full filter string is
|
|
@@ -31,6 +30,7 @@ export declare class UIAutocompleteTextField<T = string> extends UITextField {
|
|
|
31
30
|
readonly PointerHover: "PointerHover";
|
|
32
31
|
readonly EnterDown: "EnterDown";
|
|
33
32
|
readonly EnterUp: "EnterUp";
|
|
33
|
+
readonly SpaceDown: "SpaceDown";
|
|
34
34
|
readonly EscDown: "EscDown";
|
|
35
35
|
readonly TabDown: "TabDown";
|
|
36
36
|
readonly LeftArrowDown: "LeftArrowDown";
|
|
@@ -33,7 +33,6 @@ const _UIAutocompleteTextField = class extends import_UITextField.UITextField {
|
|
|
33
33
|
this._strictSelection = import_UIObject.NO;
|
|
34
34
|
this._isValid = import_UIObject.YES;
|
|
35
35
|
this._userHasNavigatedDropdown = import_UIObject.NO;
|
|
36
|
-
this._isProgrammaticTextChange = import_UIObject.NO;
|
|
37
36
|
this.usesMultiWordAndSearch = import_UIObject.NO;
|
|
38
37
|
this._dropdownView = this.newDropdownView();
|
|
39
38
|
this._dropdownView.didSelectItem = (item) => {
|
|
@@ -45,11 +44,6 @@ const _UIAutocompleteTextField = class extends import_UITextField.UITextField {
|
|
|
45
44
|
textBeforeFocus = this.text;
|
|
46
45
|
itemBeforeFocus = this.selectedItem;
|
|
47
46
|
this._userHasNavigatedDropdown = import_UIObject.NO;
|
|
48
|
-
if (!this._selectedItem) {
|
|
49
|
-
this._isProgrammaticTextChange = import_UIObject.YES;
|
|
50
|
-
this.text = "";
|
|
51
|
-
this._isProgrammaticTextChange = import_UIObject.NO;
|
|
52
|
-
}
|
|
53
47
|
this.openDropdown();
|
|
54
48
|
this.textElementView.viewHTMLElement.select();
|
|
55
49
|
const matchIndex = this._dropdownView.filteredItems.findIndex(
|
|
@@ -64,9 +58,7 @@ const _UIAutocompleteTextField = class extends import_UITextField.UITextField {
|
|
|
64
58
|
};
|
|
65
59
|
this.addTargetForControlEvent(import_UITextField.UITextField.controlEvent.TextChange, () => {
|
|
66
60
|
this._selectedItem = void 0;
|
|
67
|
-
|
|
68
|
-
this._userHasNavigatedDropdown = this.text.length > 0;
|
|
69
|
-
}
|
|
61
|
+
this._userHasNavigatedDropdown = this.text.length > 0;
|
|
70
62
|
this.updateFilteredItems();
|
|
71
63
|
if (!this._isDropdownOpen) {
|
|
72
64
|
this.openDropdown();
|
|
@@ -100,12 +92,11 @@ const _UIAutocompleteTextField = class extends import_UITextField.UITextField {
|
|
|
100
92
|
}
|
|
101
93
|
});
|
|
102
94
|
this.addTargetForControlEvent(import_UIView.UIView.controlEvent.TabDown, (sender, event) => {
|
|
103
|
-
if (this._isDropdownOpen) {
|
|
95
|
+
if (this._isDropdownOpen && this._userHasNavigatedDropdown) {
|
|
104
96
|
const highlightedItem = this._dropdownView.highlightedItem;
|
|
105
|
-
if ((0, import_UIObject.IS)(highlightedItem)
|
|
97
|
+
if ((0, import_UIObject.IS)(highlightedItem)) {
|
|
98
|
+
event.preventDefault();
|
|
106
99
|
this.commitSelection(highlightedItem);
|
|
107
|
-
} else {
|
|
108
|
-
this.closeDropdown();
|
|
109
100
|
}
|
|
110
101
|
}
|
|
111
102
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../scripts/UIAutocompleteTextField.ts"],
|
|
4
|
-
"sourcesContent": ["import { UIAutocompleteDropdownView } from \"./UIAutocompleteDropdownView\"\nimport { UIAutocompleteItem } from \"./UIAutocompleteRowView\"\nimport { IS, IS_NOT, NO, YES } from \"./UIObject\"\nimport { UITextField } from \"./UITextField\"\nimport { UIView, UIViewAddControlEventTargetObject } from \"./UIView\"\n\n\nexport class UIAutocompleteTextField<T = string> extends UITextField {\n \n _autocompleteItems: UIAutocompleteItem<T>[] = []\n _selectedItem?: UIAutocompleteItem<T>\n _dropdownView: UIAutocompleteDropdownView<T>\n _isDropdownOpen: boolean = NO\n _strictSelection: boolean = NO\n _isValid: boolean = YES\n // Set to YES only when the user has explicitly interacted with the dropdown\n // (typed text or navigated with arrow keys). Prevents Tab-to-focus from\n // auto-committing the first item.\n _userHasNavigatedDropdown: boolean = NO\n // Set to YES while we are programmatically clearing the text field on focus\n // so the TextChange handler does not treat it as a user-initiated change.\n _isProgrammaticTextChange: boolean = NO\n \n /**\n * When YES, the filter text is split on whitespace and all words must appear\n * in the item label (AND logic). When NO (default), the full filter string is\n * matched as a single substring.\n */\n usesMultiWordAndSearch: boolean = NO\n \n \n static override controlEvent = Object.assign({}, UITextField.controlEvent, {\n \"SelectionDidChange\": \"SelectionDidChange\"\n })\n \n override get controlEventTargetAccumulator(): UIViewAddControlEventTargetObject<typeof UIAutocompleteTextField> {\n return (super.controlEventTargetAccumulator as any)\n }\n \n \n constructor(elementID?: string) {\n \n super(elementID)\n \n this._dropdownView = this.newDropdownView()\n \n this._dropdownView.didSelectItem = (item) => {\n this.commitSelection(item)\n }\n \n let textBeforeFocus = this.text\n let itemBeforeFocus = this.selectedItem\n \n // Open dropdown on focus.\n // If a selection is already committed we keep the confirmed text visible\n // and do not clear it \u2014 this covers Tab-into-field after a prior selection,\n // as well as returning focus after commitSelection.\n this.controlEventTargetAccumulator.Focus = () => {\n textBeforeFocus = this.text\n itemBeforeFocus = this.selectedItem\n this._userHasNavigatedDropdown = NO\n if (!this._selectedItem) {\n this._isProgrammaticTextChange = YES\n this.text = \"\"\n this._isProgrammaticTextChange = NO\n }\n this.openDropdown()\n this.textElementView.viewHTMLElement.select()\n const matchIndex = this._dropdownView.filteredItems.findIndex(\n item => item.label === textBeforeFocus\n )\n if (matchIndex !== -1) {\n this._dropdownView.highlightedRowIndex = matchIndex\n }\n }\n \n // Close on blur\n this.controlEventTargetAccumulator.Blur = () => {\n this.closeDropdown()\n }\n \n // Filter on text change\n this.addTargetForControlEvent(UITextField.controlEvent.TextChange, () => {\n this._selectedItem = undefined\n if (!this._isProgrammaticTextChange) {\n this._userHasNavigatedDropdown = this.text.length > 0\n }\n this.updateFilteredItems()\n if (!this._isDropdownOpen) {\n this.openDropdown()\n }\n })\n \n // Keyboard navigation: down arrow\n this.textElementView.addTargetForControlEvent(UIView.controlEvent.DownArrowDown, (sender, event) => {\n event.preventDefault()\n if (!this._isDropdownOpen) {\n this.openDropdown()\n return\n }\n this._userHasNavigatedDropdown = YES\n const maxIndex = this._dropdownView.filteredItems.length - 1\n if (this._dropdownView.highlightedRowIndex < maxIndex) {\n this._dropdownView.highlightedRowIndex = this._dropdownView.highlightedRowIndex + 1\n }\n })\n \n // Keyboard navigation: up arrow\n this.textElementView.addTargetForControlEvent(UIView.controlEvent.UpArrowDown, (sender, event) => {\n event.preventDefault()\n this._userHasNavigatedDropdown = YES\n if (this._dropdownView.highlightedRowIndex > 0) {\n this._dropdownView.highlightedRowIndex = this._dropdownView.highlightedRowIndex - 1\n }\n })\n \n // Enter: commit focused item\n this.addTargetForControlEvent(UIView.controlEvent.EnterDown, () => {\n const highlightedItem = this._dropdownView.highlightedItem\n if (IS(highlightedItem)) {\n this.commitSelection(highlightedItem)\n }\n else if (this._isDropdownOpen) {\n this.closeDropdown()\n }\n })\n \n // Tab: commit highlighted item only if the user has explicitly interacted\n // with the dropdown (typed or used arrow keys). This prevents tabbing\n // through the form from silently committing the first suggestion.\n this.addTargetForControlEvent(UIView.controlEvent.TabDown, (sender, event) => {\n if (this._isDropdownOpen) {\n const highlightedItem = this._dropdownView.highlightedItem\n if (IS(highlightedItem) && this._userHasNavigatedDropdown) {\n this.commitSelection(highlightedItem)\n }\n else {\n this.closeDropdown()\n }\n }\n })\n \n // Escape: dismiss dropdown\n this.addTargetForControlEvent(UIView.controlEvent.EscDown, () => {\n if (this._isDropdownOpen) {\n this.closeDropdown()\n if (this.strictSelection) {\n this.commitSelection(itemBeforeFocus as any)\n }\n else {\n this.text = textBeforeFocus\n }\n }\n })\n \n }\n \n \n /** Override in subclass to provide a custom dropdown view. */\n newDropdownView(): UIAutocompleteDropdownView<T> {\n return new UIAutocompleteDropdownView<T>(\n this.elementID ? this.elementID + \"Dropdown\" : undefined\n )\n }\n \n \n // MARK: - Selection\n \n get selectedItem(): T | undefined {\n return this._selectedItem?.value\n }\n \n \n get strictSelection(): boolean {\n return this._strictSelection\n }\n \n set strictSelection(strict: boolean) {\n this._strictSelection = strict\n this.updateValidationVisuals()\n }\n \n \n commitSelection(item: UIAutocompleteItem<T>) {\n \n // Set the selection state and close the dropdown without blurring.\n // Keeping focus on this view means the next Tab press is handled by\n // our TabDown handler rather than being picked up natively by the browser.\n this._selectedItem = item\n this.text = item.label\n this.closeDropdown()\n this.updateValidationVisuals()\n this.sendControlEventForKey(UIAutocompleteTextField.controlEvent.SelectionDidChange)\n \n }\n \n \n // MARK: - Data\n \n /** Convenience: set string suggestions. Each string becomes { label: s, value: s }. */\n set autocompleteStrings(strings: string[]) {\n this._autocompleteItems = strings.map(s => ({\n label: s,\n value: s as unknown as T\n }))\n this.updateFilteredItems()\n }\n \n get autocompleteStrings(): string[] {\n return this._autocompleteItems.map(item => item.label)\n }\n \n set autocompleteData(items: UIAutocompleteItem<T>[]) {\n this._autocompleteItems = items\n this.updateFilteredItems()\n }\n \n get autocompleteData(): UIAutocompleteItem<T>[] {\n return this._autocompleteItems\n }\n \n \n // MARK: - Filtering\n \n /**\n * Splits the given lowercase-trimmed filter text into individual words when\n * usesMultiWordAndSearch is YES, or returns it as a single-element array otherwise.\n * Returns an empty array when the input is empty.\n */\n _filterWordsFromText(filterText: string): string[] {\n if (filterText.length === 0) {\n return []\n }\n if (this.usesMultiWordAndSearch) {\n return filterText.split(/\\s+/).filter(word => word.length > 0)\n }\n return [filterText]\n }\n \n \n /**\n * Returns true when the given label (already lowercased) satisfies all filter\n * words \u2014 i.e. every word appears somewhere in the label.\n */\n _labelMatchesFilterWords(label: string, filterWords: string[]): boolean {\n return filterWords.every(word => label.includes(word))\n }\n \n \n /**\n * Returns true when the character immediately before `position` in `label`\n * is a word separator (or the position is at the start of the string).\n * Used to give a bonus to matches that start at a word boundary.\n */\n _isWordBoundary(label: string, position: number): boolean {\n if (position === 0) {\n return YES\n }\n const charBefore = label[position - 1]\n return \" -/\\\\|._,;:()[]\".includes(charBefore)\n }\n \n \n /**\n * Scores a label against the filter words. Lower score = better match.\n *\n * Scoring factors (in priority order):\n * 1. Non-sequential penalty \u2014 words must appear in typed order to avoid\n * a large penalty that pushes them below all sequential matches.\n * 2. Per-word boundary score \u2014 for each filter word, a mid-word match\n * scores worse than a word-boundary match. The sum across all words\n * determines the boundary tier.\n * 3. Position of the first matched word \u2014 within the same boundary tier,\n * earlier appearances rank higher.\n * 4. Total label length \u2014 shorter labels are more specific (tiebreaker).\n *\n * Example: query \"p\u00F5 pu\"\n * \"P\u00F5hjavee puhastusvahendid\" \u2192 \"p\u00F5\" at boundary(0), \"pu\" at boundary(9) \u2192 low boundary score\n * \"p\u00F5randapuhastusvahendid\" \u2192 \"p\u00F5\" at boundary(0), \"pu\" mid-word(7) \u2192 higher boundary score\n * \u2192 \"P\u00F5hjavee puhastusvahendid\" ranks first.\n */\n _scoreLabel(label: string, filterWords: string[]): number {\n \n if (filterWords.length === 0) {\n return label.length\n }\n \n // --- Sequential check ---\n // Scan left-to-right; if all words appear in order record the positions.\n let cursor = 0\n let isSequential = YES\n const sequentialPositions: number[] = []\n for (const word of filterWords) {\n const position = label.indexOf(word, cursor)\n if (position === -1) {\n isSequential = NO\n break\n }\n sequentialPositions.push(position)\n cursor = position + word.length\n }\n \n // --- Boundary score ---\n // For each filter word find its best (leftmost) match and check whether\n // it lands on a word boundary. Non-boundary matches incur a per-word\n // penalty of 1, so the boundary score is 0..filterWords.length.\n let boundaryScore = 0\n for (const word of filterWords) {\n const position = label.indexOf(word)\n if (position !== -1 && !this._isWordBoundary(label, position)) {\n boundaryScore += 1\n }\n }\n \n // Position of the first word's earliest match.\n const firstMatchPosition = label.indexOf(filterWords[0])\n \n // Compose score \u2014 each tier must not overflow into the next:\n // Non-sequential penalty : 10 000 000 (dominates everything)\n // Boundary score : 10 000 (per word, max ~10 words \u2192 100 000 max, safe)\n // First-match position : 100 (labels rarely exceed 200 chars)\n // Label length : 1 (tiebreaker)\n const sequentialPenalty = isSequential ? 0 : 10_000_000\n \n return sequentialPenalty +\n boundaryScore * 10_000 +\n firstMatchPosition * 100 +\n label.length\n \n }\n \n \n updateFilteredItems() {\n \n const rawFilterText = this.text.toLowerCase().trim()\n const filterWords = this._filterWordsFromText(rawFilterText)\n \n let filtered: UIAutocompleteItem<T>[]\n \n if (filterWords.length === 0) {\n filtered = this._autocompleteItems\n }\n else {\n filtered = this._autocompleteItems\n .filter(item => this._labelMatchesFilterWords(item.label.toLowerCase(), filterWords))\n .map((item, originalIndex) => ({ item, originalIndex, score: this._scoreLabel(item.label.toLowerCase(), filterWords) }))\n .sort((a, b) => a.score - b.score || a.originalIndex - b.originalIndex)\n .map(({ item }) => item)\n }\n \n // If the only remaining result is an exact match for the current text,\n // the user has already made their selection \u2014 no need to show the dropdown.\n const isExactSingleMatch = filtered.length === 1 &&\n filtered[0].label.toLowerCase() === rawFilterText\n \n this._dropdownView.filterWords = filterWords\n this._dropdownView.filteredItems = isExactSingleMatch ? [] : filtered\n \n if (this._dropdownView.filteredItems.length > 0) {\n this._dropdownView.highlightedRowIndex = 0\n }\n \n if (this._isDropdownOpen) {\n this._dropdownView.showAnchoredToView(this)\n }\n \n }\n \n \n // MARK: - Dropdown Lifecycle\n \n openDropdown() {\n \n if (this._isDropdownOpen) {\n return\n }\n \n this._isDropdownOpen = YES\n this._dropdownView.filterWords = []\n this.updateFilteredItems()\n this._dropdownView.showAnchoredToView(this)\n \n }\n \n closeDropdown() {\n \n if (!this._isDropdownOpen) {\n return\n }\n \n this._isDropdownOpen = NO\n this._dropdownView.dismiss()\n \n // In strict mode, clear text if it doesn't match any item\n if (this._strictSelection && IS_NOT(this._selectedItem)) {\n const currentText = this.text.trim()\n if (currentText.length > 0) {\n const matchingItem = this._autocompleteItems.find(\n item => item.label === currentText\n )\n if (IS(matchingItem)) {\n this._selectedItem = matchingItem\n }\n else {\n this.text = \"\"\n this._selectedItem = undefined\n }\n }\n }\n \n this.updateValidationVisuals()\n \n }\n \n \n // MARK: - Validation\n \n /** Whether the current text is valid given the strictSelection setting. */\n get isValid(): boolean {\n \n if (!this._strictSelection) {\n return YES\n }\n \n const currentText = this.text.trim()\n \n if (currentText.length === 0) {\n return YES\n }\n \n return this._autocompleteItems.some(item => item.label === currentText)\n \n }\n \n \n /**\n * Hook for subclasses to apply custom visual styling based on validation state.\n * Called after dropdown closes and after selection changes.\n */\n updateValidationVisuals() {\n // Base implementation does nothing. Subclasses override.\n }\n \n \n // MARK: - Cleanup\n \n override wasRemovedFromViewTree() {\n \n super.wasRemovedFromViewTree()\n \n this._dropdownView.removeFromSuperview()\n \n }\n \n \n // MARK: - Layout\n \n override layoutSubviews() {\n \n super.layoutSubviews()\n \n if (this._isDropdownOpen) {\n this._dropdownView.showAnchoredToView(this)\n }\n \n }\n \n \n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wCAA2C;AAE3C,sBAAoC;AACpC,yBAA4B;AAC5B,oBAA0D;AAGnD,MAAM,2BAAN,cAAkD,+BAAY;AAAA,
|
|
4
|
+
"sourcesContent": ["import { UIAutocompleteDropdownView } from \"./UIAutocompleteDropdownView\"\nimport { UIAutocompleteItem } from \"./UIAutocompleteRowView\"\nimport { IS, IS_NOT, NO, YES } from \"./UIObject\"\nimport { UITextField } from \"./UITextField\"\nimport { UIView, UIViewAddControlEventTargetObject } from \"./UIView\"\n\n\nexport class UIAutocompleteTextField<T = string> extends UITextField {\n \n _autocompleteItems: UIAutocompleteItem<T>[] = []\n _selectedItem?: UIAutocompleteItem<T>\n _dropdownView: UIAutocompleteDropdownView<T>\n _isDropdownOpen: boolean = NO\n _strictSelection: boolean = NO\n _isValid: boolean = YES\n // Set to YES only when the user has explicitly interacted with the dropdown\n // (typed text or navigated with arrow keys). Prevents Tab-to-focus from\n // auto-committing the first item.\n _userHasNavigatedDropdown: boolean = NO\n \n /**\n * When YES, the filter text is split on whitespace and all words must appear\n * in the item label (AND logic). When NO (default), the full filter string is\n * matched as a single substring.\n */\n usesMultiWordAndSearch: boolean = NO\n \n \n static override controlEvent = Object.assign({}, UITextField.controlEvent, {\n \"SelectionDidChange\": \"SelectionDidChange\"\n })\n \n override get controlEventTargetAccumulator(): UIViewAddControlEventTargetObject<typeof UIAutocompleteTextField> {\n return (super.controlEventTargetAccumulator as any)\n }\n \n \n constructor(elementID?: string) {\n \n super(elementID)\n \n this._dropdownView = this.newDropdownView()\n \n this._dropdownView.didSelectItem = (item) => {\n this.commitSelection(item)\n }\n \n let textBeforeFocus = this.text\n let itemBeforeFocus = this.selectedItem\n \n // Open dropdown on focus.\n // If a selection is already committed we keep the confirmed text visible\n // and do not clear it \u2014 this covers Tab-into-field after a prior selection,\n // as well as returning focus after commitSelection.\n this.controlEventTargetAccumulator.Focus = () => {\n textBeforeFocus = this.text\n itemBeforeFocus = this.selectedItem\n this._userHasNavigatedDropdown = NO\n this.openDropdown()\n this.textElementView.viewHTMLElement.select()\n const matchIndex = this._dropdownView.filteredItems.findIndex(\n item => item.label === textBeforeFocus\n )\n if (matchIndex !== -1) {\n this._dropdownView.highlightedRowIndex = matchIndex\n }\n }\n \n // Close on blur\n this.controlEventTargetAccumulator.Blur = () => {\n this.closeDropdown()\n }\n \n // Filter on text change\n this.addTargetForControlEvent(UITextField.controlEvent.TextChange, () => {\n this._selectedItem = undefined\n this._userHasNavigatedDropdown = this.text.length > 0\n this.updateFilteredItems()\n if (!this._isDropdownOpen) {\n this.openDropdown()\n }\n })\n \n // Keyboard navigation: down arrow\n this.textElementView.addTargetForControlEvent(UIView.controlEvent.DownArrowDown, (sender, event) => {\n event.preventDefault()\n if (!this._isDropdownOpen) {\n this.openDropdown()\n return\n }\n this._userHasNavigatedDropdown = YES\n const maxIndex = this._dropdownView.filteredItems.length - 1\n if (this._dropdownView.highlightedRowIndex < maxIndex) {\n this._dropdownView.highlightedRowIndex = this._dropdownView.highlightedRowIndex + 1\n }\n })\n \n // Keyboard navigation: up arrow\n this.textElementView.addTargetForControlEvent(UIView.controlEvent.UpArrowDown, (sender, event) => {\n event.preventDefault()\n this._userHasNavigatedDropdown = YES\n if (this._dropdownView.highlightedRowIndex > 0) {\n this._dropdownView.highlightedRowIndex = this._dropdownView.highlightedRowIndex - 1\n }\n })\n \n // Enter: commit focused item\n this.addTargetForControlEvent(UIView.controlEvent.EnterDown, () => {\n const highlightedItem = this._dropdownView.highlightedItem\n if (IS(highlightedItem)) {\n this.commitSelection(highlightedItem)\n }\n else if (this._isDropdownOpen) {\n this.closeDropdown()\n }\n })\n \n // Tab: commit highlighted item only if the user has explicitly interacted\n // with the dropdown (typed or used arrow keys). This prevents tabbing\n // through the form from silently committing the first suggestion.\n // When the user has not navigated, we do NOT consume the event \u2014 the\n // dropdown will close via the Blur handler and RHPageFocusManager will\n // handle the Tab navigation normally.\n this.addTargetForControlEvent(UIView.controlEvent.TabDown, (sender, event) => {\n if (this._isDropdownOpen && this._userHasNavigatedDropdown) {\n const highlightedItem = this._dropdownView.highlightedItem\n if (IS(highlightedItem)) {\n event.preventDefault()\n this.commitSelection(highlightedItem)\n }\n }\n })\n \n // Escape: dismiss dropdown\n this.addTargetForControlEvent(UIView.controlEvent.EscDown, () => {\n if (this._isDropdownOpen) {\n this.closeDropdown()\n if (this.strictSelection) {\n this.commitSelection(itemBeforeFocus as any)\n }\n else {\n this.text = textBeforeFocus\n }\n }\n })\n \n }\n \n \n /** Override in subclass to provide a custom dropdown view. */\n newDropdownView(): UIAutocompleteDropdownView<T> {\n return new UIAutocompleteDropdownView<T>(\n this.elementID ? this.elementID + \"Dropdown\" : undefined\n )\n }\n \n \n // MARK: - Selection\n \n get selectedItem(): T | undefined {\n return this._selectedItem?.value\n }\n \n \n get strictSelection(): boolean {\n return this._strictSelection\n }\n \n set strictSelection(strict: boolean) {\n this._strictSelection = strict\n this.updateValidationVisuals()\n }\n \n \n commitSelection(item: UIAutocompleteItem<T>) {\n \n // Set the selection state and close the dropdown without blurring.\n // Keeping focus on this view means the next Tab press is handled by\n // our TabDown handler rather than being picked up natively by the browser.\n this._selectedItem = item\n this.text = item.label\n this.closeDropdown()\n this.updateValidationVisuals()\n this.sendControlEventForKey(UIAutocompleteTextField.controlEvent.SelectionDidChange)\n \n }\n \n \n // MARK: - Data\n \n /** Convenience: set string suggestions. Each string becomes { label: s, value: s }. */\n set autocompleteStrings(strings: string[]) {\n this._autocompleteItems = strings.map(s => ({\n label: s,\n value: s as unknown as T\n }))\n this.updateFilteredItems()\n }\n \n get autocompleteStrings(): string[] {\n return this._autocompleteItems.map(item => item.label)\n }\n \n set autocompleteData(items: UIAutocompleteItem<T>[]) {\n this._autocompleteItems = items\n this.updateFilteredItems()\n }\n \n get autocompleteData(): UIAutocompleteItem<T>[] {\n return this._autocompleteItems\n }\n \n \n // MARK: - Filtering\n \n /**\n * Splits the given lowercase-trimmed filter text into individual words when\n * usesMultiWordAndSearch is YES, or returns it as a single-element array otherwise.\n * Returns an empty array when the input is empty.\n */\n _filterWordsFromText(filterText: string): string[] {\n if (filterText.length === 0) {\n return []\n }\n if (this.usesMultiWordAndSearch) {\n return filterText.split(/\\s+/).filter(word => word.length > 0)\n }\n return [filterText]\n }\n \n \n /**\n * Returns true when the given label (already lowercased) satisfies all filter\n * words \u2014 i.e. every word appears somewhere in the label.\n */\n _labelMatchesFilterWords(label: string, filterWords: string[]): boolean {\n return filterWords.every(word => label.includes(word))\n }\n \n \n /**\n * Returns true when the character immediately before `position` in `label`\n * is a word separator (or the position is at the start of the string).\n * Used to give a bonus to matches that start at a word boundary.\n */\n _isWordBoundary(label: string, position: number): boolean {\n if (position === 0) {\n return YES\n }\n const charBefore = label[position - 1]\n return \" -/\\\\|._,;:()[]\".includes(charBefore)\n }\n \n \n /**\n * Scores a label against the filter words. Lower score = better match.\n *\n * Scoring factors (in priority order):\n * 1. Non-sequential penalty \u2014 words must appear in typed order to avoid\n * a large penalty that pushes them below all sequential matches.\n * 2. Per-word boundary score \u2014 for each filter word, a mid-word match\n * scores worse than a word-boundary match. The sum across all words\n * determines the boundary tier.\n * 3. Position of the first matched word \u2014 within the same boundary tier,\n * earlier appearances rank higher.\n * 4. Total label length \u2014 shorter labels are more specific (tiebreaker).\n *\n * Example: query \"p\u00F5 pu\"\n * \"P\u00F5hjavee puhastusvahendid\" \u2192 \"p\u00F5\" at boundary(0), \"pu\" at boundary(9) \u2192 low boundary score\n * \"p\u00F5randapuhastusvahendid\" \u2192 \"p\u00F5\" at boundary(0), \"pu\" mid-word(7) \u2192 higher boundary score\n * \u2192 \"P\u00F5hjavee puhastusvahendid\" ranks first.\n */\n _scoreLabel(label: string, filterWords: string[]): number {\n \n if (filterWords.length === 0) {\n return label.length\n }\n \n // --- Sequential check ---\n // Scan left-to-right; if all words appear in order record the positions.\n let cursor = 0\n let isSequential = YES\n const sequentialPositions: number[] = []\n for (const word of filterWords) {\n const position = label.indexOf(word, cursor)\n if (position === -1) {\n isSequential = NO\n break\n }\n sequentialPositions.push(position)\n cursor = position + word.length\n }\n \n // --- Boundary score ---\n // For each filter word find its best (leftmost) match and check whether\n // it lands on a word boundary. Non-boundary matches incur a per-word\n // penalty of 1, so the boundary score is 0..filterWords.length.\n let boundaryScore = 0\n for (const word of filterWords) {\n const position = label.indexOf(word)\n if (position !== -1 && !this._isWordBoundary(label, position)) {\n boundaryScore += 1\n }\n }\n \n // Position of the first word's earliest match.\n const firstMatchPosition = label.indexOf(filterWords[0])\n \n // Compose score \u2014 each tier must not overflow into the next:\n // Non-sequential penalty : 10 000 000 (dominates everything)\n // Boundary score : 10 000 (per word, max ~10 words \u2192 100 000 max, safe)\n // First-match position : 100 (labels rarely exceed 200 chars)\n // Label length : 1 (tiebreaker)\n const sequentialPenalty = isSequential ? 0 : 10_000_000\n \n return sequentialPenalty +\n boundaryScore * 10_000 +\n firstMatchPosition * 100 +\n label.length\n \n }\n \n \n updateFilteredItems() {\n \n const rawFilterText = this.text.toLowerCase().trim()\n const filterWords = this._filterWordsFromText(rawFilterText)\n \n let filtered: UIAutocompleteItem<T>[]\n \n if (filterWords.length === 0) {\n filtered = this._autocompleteItems\n }\n else {\n filtered = this._autocompleteItems\n .filter(item => this._labelMatchesFilterWords(item.label.toLowerCase(), filterWords))\n .map((item, originalIndex) => ({ item, originalIndex, score: this._scoreLabel(item.label.toLowerCase(), filterWords) }))\n .sort((a, b) => a.score - b.score || a.originalIndex - b.originalIndex)\n .map(({ item }) => item)\n }\n \n // If the only remaining result is an exact match for the current text,\n // the user has already made their selection \u2014 no need to show the dropdown.\n const isExactSingleMatch = filtered.length === 1 &&\n filtered[0].label.toLowerCase() === rawFilterText\n \n this._dropdownView.filterWords = filterWords\n this._dropdownView.filteredItems = isExactSingleMatch ? [] : filtered\n \n if (this._dropdownView.filteredItems.length > 0) {\n this._dropdownView.highlightedRowIndex = 0\n }\n \n if (this._isDropdownOpen) {\n this._dropdownView.showAnchoredToView(this)\n }\n \n }\n \n \n // MARK: - Dropdown Lifecycle\n \n openDropdown() {\n \n if (this._isDropdownOpen) {\n return\n }\n \n this._isDropdownOpen = YES\n this._dropdownView.filterWords = []\n this.updateFilteredItems()\n this._dropdownView.showAnchoredToView(this)\n \n }\n \n closeDropdown() {\n \n if (!this._isDropdownOpen) {\n return\n }\n \n this._isDropdownOpen = NO\n this._dropdownView.dismiss()\n \n // In strict mode, clear text if it doesn't match any item\n if (this._strictSelection && IS_NOT(this._selectedItem)) {\n const currentText = this.text.trim()\n if (currentText.length > 0) {\n const matchingItem = this._autocompleteItems.find(\n item => item.label === currentText\n )\n if (IS(matchingItem)) {\n this._selectedItem = matchingItem\n }\n else {\n this.text = \"\"\n this._selectedItem = undefined\n }\n }\n }\n \n this.updateValidationVisuals()\n \n }\n \n \n // MARK: - Validation\n \n /** Whether the current text is valid given the strictSelection setting. */\n get isValid(): boolean {\n \n if (!this._strictSelection) {\n return YES\n }\n \n const currentText = this.text.trim()\n \n if (currentText.length === 0) {\n return YES\n }\n \n return this._autocompleteItems.some(item => item.label === currentText)\n \n }\n \n \n /**\n * Hook for subclasses to apply custom visual styling based on validation state.\n * Called after dropdown closes and after selection changes.\n */\n updateValidationVisuals() {\n // Base implementation does nothing. Subclasses override.\n }\n \n \n // MARK: - Cleanup\n \n override wasRemovedFromViewTree() {\n \n super.wasRemovedFromViewTree()\n \n this._dropdownView.removeFromSuperview()\n \n }\n \n \n // MARK: - Layout\n \n override layoutSubviews() {\n \n super.layoutSubviews()\n \n if (this._isDropdownOpen) {\n this._dropdownView.showAnchoredToView(this)\n }\n \n }\n \n \n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,5 +1,57 @@
|
|
|
1
1
|
import { UIView, UIViewBroadcastEvent } from "./UIView";
|
|
2
2
|
export declare class UIBaseButton extends UIView {
|
|
3
|
+
static controlEvent: {
|
|
4
|
+
readonly PointerDown: "PointerDown";
|
|
5
|
+
readonly PointerMove: "PointerMove";
|
|
6
|
+
readonly PointerDrag: "PointerDrag";
|
|
7
|
+
readonly PointerLeave: "PointerLeave";
|
|
8
|
+
readonly PointerEnter: "PointerEnter";
|
|
9
|
+
readonly PointerUpInside: "PointerUpInside";
|
|
10
|
+
readonly PointerTap: "PointerTap";
|
|
11
|
+
readonly PointerUp: "PointerUp";
|
|
12
|
+
readonly MultipleTouches: "PointerZoom";
|
|
13
|
+
readonly PointerCancel: "PointerCancel";
|
|
14
|
+
readonly PointerHover: "PointerHover";
|
|
15
|
+
readonly EnterDown: "EnterDown";
|
|
16
|
+
readonly EnterUp: "EnterUp";
|
|
17
|
+
readonly SpaceDown: "SpaceDown";
|
|
18
|
+
readonly EscDown: "EscDown";
|
|
19
|
+
readonly TabDown: "TabDown";
|
|
20
|
+
readonly LeftArrowDown: "LeftArrowDown";
|
|
21
|
+
readonly RightArrowDown: "RightArrowDown";
|
|
22
|
+
readonly DownArrowDown: "DownArrowDown";
|
|
23
|
+
readonly UpArrowDown: "UpArrowDown";
|
|
24
|
+
readonly Focus: "Focus";
|
|
25
|
+
readonly Blur: "Blur";
|
|
26
|
+
} & {
|
|
27
|
+
readonly PrimaryActionTriggered: "PrimaryActionTriggered";
|
|
28
|
+
};
|
|
29
|
+
controlEvent: {
|
|
30
|
+
readonly PointerDown: "PointerDown";
|
|
31
|
+
readonly PointerMove: "PointerMove";
|
|
32
|
+
readonly PointerDrag: "PointerDrag";
|
|
33
|
+
readonly PointerLeave: "PointerLeave";
|
|
34
|
+
readonly PointerEnter: "PointerEnter";
|
|
35
|
+
readonly PointerUpInside: "PointerUpInside";
|
|
36
|
+
readonly PointerTap: "PointerTap";
|
|
37
|
+
readonly PointerUp: "PointerUp";
|
|
38
|
+
readonly MultipleTouches: "PointerZoom";
|
|
39
|
+
readonly PointerCancel: "PointerCancel";
|
|
40
|
+
readonly PointerHover: "PointerHover";
|
|
41
|
+
readonly EnterDown: "EnterDown";
|
|
42
|
+
readonly EnterUp: "EnterUp";
|
|
43
|
+
readonly SpaceDown: "SpaceDown";
|
|
44
|
+
readonly EscDown: "EscDown";
|
|
45
|
+
readonly TabDown: "TabDown";
|
|
46
|
+
readonly LeftArrowDown: "LeftArrowDown";
|
|
47
|
+
readonly RightArrowDown: "RightArrowDown";
|
|
48
|
+
readonly DownArrowDown: "DownArrowDown";
|
|
49
|
+
readonly UpArrowDown: "UpArrowDown";
|
|
50
|
+
readonly Focus: "Focus";
|
|
51
|
+
readonly Blur: "Blur";
|
|
52
|
+
} & {
|
|
53
|
+
readonly PrimaryActionTriggered: "PrimaryActionTriggered";
|
|
54
|
+
};
|
|
3
55
|
_selected: boolean;
|
|
4
56
|
_highlighted: boolean;
|
|
5
57
|
_isPointerInside: boolean;
|
|
@@ -24,9 +24,10 @@ module.exports = __toCommonJS(UIBaseButton_exports);
|
|
|
24
24
|
var import_UIColor = require("./UIColor");
|
|
25
25
|
var import_UIObject = require("./UIObject");
|
|
26
26
|
var import_UIView = require("./UIView");
|
|
27
|
-
class
|
|
27
|
+
const _UIBaseButton = class extends import_UIView.UIView {
|
|
28
28
|
constructor(elementID, elementType) {
|
|
29
29
|
super(elementID, void 0, elementType);
|
|
30
|
+
this.controlEvent = _UIBaseButton.controlEvent;
|
|
30
31
|
this._selected = import_UIObject.NO;
|
|
31
32
|
this._highlighted = import_UIObject.NO;
|
|
32
33
|
this._isToggleable = import_UIObject.NO;
|
|
@@ -73,6 +74,13 @@ class UIBaseButton extends import_UIView.UIView {
|
|
|
73
74
|
this.addTargetForControlEvent(import_UIView.UIView.controlEvent.EnterDown, () => {
|
|
74
75
|
setHighlighted();
|
|
75
76
|
setNotHighlightedWithMinimumDuration();
|
|
77
|
+
this.sendControlEventForKey(_UIBaseButton.controlEvent.PrimaryActionTriggered, import_UIObject.nil);
|
|
78
|
+
});
|
|
79
|
+
this.addTargetForControlEvent(import_UIView.UIView.controlEvent.SpaceDown, (sender, event) => {
|
|
80
|
+
event.preventDefault();
|
|
81
|
+
setHighlighted();
|
|
82
|
+
setNotHighlightedWithMinimumDuration();
|
|
83
|
+
this.sendControlEventForKey(_UIBaseButton.controlEvent.PrimaryActionTriggered, import_UIObject.nil);
|
|
76
84
|
});
|
|
77
85
|
this.addTargetForControlEvent(
|
|
78
86
|
import_UIView.UIView.controlEvent.Focus,
|
|
@@ -91,7 +99,7 @@ class UIBaseButton extends import_UIView.UIView {
|
|
|
91
99
|
this.style.cursor = "pointer";
|
|
92
100
|
this.nativeSelectionEnabled = import_UIObject.NO;
|
|
93
101
|
this.addTargetForControlEvents([
|
|
94
|
-
|
|
102
|
+
_UIBaseButton.controlEvent.PrimaryActionTriggered,
|
|
95
103
|
import_UIView.UIView.controlEvent.PointerUpInside
|
|
96
104
|
], () => {
|
|
97
105
|
if (this.isToggleable) {
|
|
@@ -219,6 +227,9 @@ class UIBaseButton extends import_UIView.UIView {
|
|
|
219
227
|
const asd = 1;
|
|
220
228
|
} else {
|
|
221
229
|
super.sendControlEventForKey(eventKey, nativeEvent);
|
|
230
|
+
if (eventKey == import_UIView.UIView.controlEvent.PointerUpInside) {
|
|
231
|
+
super.sendControlEventForKey(_UIBaseButton.controlEvent.PrimaryActionTriggered, nativeEvent);
|
|
232
|
+
}
|
|
222
233
|
}
|
|
223
234
|
}
|
|
224
235
|
static getEventCoordinatesInDocument(touchOrMouseEvent) {
|
|
@@ -268,7 +279,11 @@ class UIBaseButton extends import_UIView.UIView {
|
|
|
268
279
|
);
|
|
269
280
|
return coordinatesInElement;
|
|
270
281
|
}
|
|
271
|
-
}
|
|
282
|
+
};
|
|
283
|
+
let UIBaseButton = _UIBaseButton;
|
|
284
|
+
UIBaseButton.controlEvent = Object.assign({}, import_UIView.UIView.controlEvent, {
|
|
285
|
+
"PrimaryActionTriggered": "PrimaryActionTriggered"
|
|
286
|
+
});
|
|
272
287
|
// Annotate the CommonJS export names for ESM import in node:
|
|
273
288
|
0 && (module.exports = {
|
|
274
289
|
UIBaseButton
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../scripts/UIBaseButton.ts"],
|
|
4
|
-
"sourcesContent": ["import { UIColor } from \"./UIColor\"\nimport { IS, nil, NO, YES } from \"./UIObject\"\nimport { UIView, UIViewBroadcastEvent } from \"./UIView\"\n\n\nexport class UIBaseButton extends UIView {\n \n _selected: boolean = NO\n _highlighted: boolean = NO\n \n override _isPointerInside: boolean\n \n \n _isToggleable: boolean = NO\n _hovered?: boolean\n _focused?: boolean\n \n \n constructor(elementID?: string, elementType?: string) {\n \n super(elementID, undefined, elementType)\n \n // Instance variables\n \n \n this._isPointerInside = NO\n \n \n const setHovered = () => {\n this.hovered = YES\n }\n this.addTargetForControlEvent(UIView.controlEvent.PointerHover, setHovered)\n \n const setNotHovered = () => {\n \n this.hovered = NO\n \n }\n \n this.addTargetForControlEvents([\n UIView.controlEvent.PointerLeave, UIView.controlEvent.PointerCancel, UIView.controlEvent.MultipleTouches\n ], setNotHovered)\n \n \n let highlightingTime: number\n const setHighlighted = () => {\n this.highlighted = YES\n highlightingTime = Date.now()\n }\n this.addTargetForControlEvent(UIView.controlEvent.PointerDown, setHighlighted)\n this.addTargetForControlEvent(UIView.controlEvent.PointerEnter, setHighlighted)\n \n const setNotHighlighted = () => {\n this.highlighted = NO\n }\n const setNotHighlightedWithMinimumDuration = () => {\n const minimumDurationInMilliseconds = 50\n const elapsedTime = Date.now() - highlightingTime\n if (minimumDurationInMilliseconds < elapsedTime) {\n this.highlighted = NO\n }\n else {\n setTimeout(() => {\n this.highlighted = NO\n }, minimumDurationInMilliseconds - elapsedTime)\n }\n }\n this.addTargetForControlEvents([\n UIView.controlEvent.PointerLeave, UIView.controlEvent.PointerCancel, UIView.controlEvent.MultipleTouches\n ], setNotHighlighted)\n this.addTargetForControlEvent(UIView.controlEvent.PointerUp, setNotHighlightedWithMinimumDuration)\n \n // Handle enter key press\n this.addTargetForControlEvent(UIView.controlEvent.EnterDown, () => {\n \n setHighlighted()\n setNotHighlightedWithMinimumDuration()\n \n })\n \n \n this.addTargetForControlEvent(\n UIView.controlEvent.Focus,\n (sender: UIView, event: Event) => {\n \n this.focused = YES\n \n }\n )\n \n this.addTargetForControlEvent(\n UIView.controlEvent.Blur,\n (sender: UIView, event: Event) => {\n \n this.focused = NO\n \n }\n )\n \n \n this.pausesPointerEvents = YES\n this.tabIndex = 1\n \n this.style.cursor = \"pointer\"\n \n //this.style.outline = \"none\";\n \n \n this.nativeSelectionEnabled = NO\n \n \n this.addTargetForControlEvents([\n UIView.controlEvent.EnterDown, UIView.controlEvent.PointerUpInside\n ], () => {\n \n if (this.isToggleable) {\n \n this.toggleSelectedState()\n \n }\n \n })\n \n }\n \n public set hovered(hovered: boolean) {\n this._hovered = hovered\n this.updateContentForCurrentState()\n }\n \n public get hovered(): boolean {\n return this._hovered ?? NO\n }\n \n public set highlighted(highlighted: boolean) {\n this._highlighted = highlighted\n this.updateContentForCurrentState()\n }\n \n public get highlighted(): boolean {\n return this._highlighted\n }\n \n public set focused(focused: boolean) {\n this._focused = focused\n if (focused) {\n this.focus()\n }\n else {\n this.blur()\n }\n this.updateContentForCurrentState()\n }\n \n public get focused(): boolean {\n return this._focused ?? NO\n }\n \n public set selected(selected: boolean) {\n this._selected = selected\n this.updateContentForCurrentState()\n }\n \n public get selected(): boolean {\n return this._selected\n }\n \n \n updateContentForCurrentState() {\n \n let updateFunction: Function = this.updateContentForNormalState\n if (this.selected && this.highlighted) {\n updateFunction = this.updateContentForSelectedAndHighlightedState\n }\n else if (this.selected) {\n updateFunction = this.updateContentForSelectedState\n }\n else if (this.focused) {\n updateFunction = this.updateContentForFocusedState\n }\n else if (this.highlighted) {\n updateFunction = this.updateContentForHighlightedState\n }\n else if (this.hovered) {\n updateFunction = this.updateContentForHoveredState\n }\n \n if (!IS(updateFunction)) {\n this.backgroundColor = UIColor.nilColor\n }\n else {\n updateFunction.call(this)\n }\n \n }\n \n updateContentForNormalState() {\n \n \n }\n \n updateContentForHoveredState() {\n \n this.updateContentForNormalState()\n \n }\n \n updateContentForFocusedState() {\n \n this.updateContentForHoveredState()\n \n }\n \n updateContentForHighlightedState() {\n \n \n }\n \n updateContentForSelectedState() {\n \n \n }\n \n updateContentForSelectedAndHighlightedState() {\n \n this.updateContentForSelectedState()\n \n }\n \n \n override set enabled(enabled: boolean) {\n super.enabled = enabled\n this.updateContentForCurrentEnabledState()\n }\n \n override get enabled() {\n return super.enabled\n }\n \n override updateContentForCurrentEnabledState() {\n \n if (this.enabled) {\n this.alpha = 1\n }\n else {\n this.alpha = 0.5\n }\n \n this.userInteractionEnabled = this.enabled\n \n }\n \n \n override addStyleClass(styleClassName: string) {\n \n super.addStyleClass(styleClassName)\n \n if (this.styleClassName != styleClassName) {\n \n this.updateContentForCurrentState.call(this)\n \n }\n \n }\n \n \n override didReceiveBroadcastEvent(event: UIViewBroadcastEvent) {\n \n super.didReceiveBroadcastEvent(event)\n \n if (event.name == UIView.broadcastEventName.PageDidScroll || event.name ==\n UIView.broadcastEventName.AddedToViewTree) {\n \n const wasHovered = this._hovered\n const wasHighlighted = this._highlighted\n \n this._hovered = NO\n this._highlighted = NO\n \n if (wasHovered || wasHighlighted) {\n this.updateContentForCurrentState()\n }\n \n }\n \n \n }\n \n \n toggleSelectedState() {\n \n \n this.selected = !this.selected\n \n \n }\n \n set isToggleable(isToggleable: boolean) {\n \n this._isToggleable = isToggleable\n \n }\n \n get isToggleable() {\n \n return this._isToggleable\n \n }\n \n \n override layoutSubviews() {\n \n super.layoutSubviews()\n \n const bounds = this.bounds\n \n \n }\n \n \n override sendControlEventForKey(eventKey: string, nativeEvent: Event) {\n \n if (eventKey == UIView.controlEvent.PointerUpInside && !this.highlighted) {\n \n // Do not send the event in this case\n //super.sendControlEventForKey(eventKey, nativeEvent);\n \n const asd = 1\n \n }\n else {\n \n super.sendControlEventForKey(eventKey, nativeEvent)\n \n }\n \n }\n \n \n static getEventCoordinatesInDocument(touchOrMouseEvent: any) {\n // http://www.quirksmode.org/js/events_properties.html\n var posx = 0\n var posy = 0\n var e = touchOrMouseEvent\n if (!e) {\n e = window.event\n }\n if (e.pageX || e.pageY) {\n posx = e.pageX\n posy = e.pageY\n }\n else if (e.clientX || e.clientY) {\n posx = e.clientX + document.body.scrollLeft\n + document.documentElement.scrollLeft\n posy = e.clientY + document.body.scrollTop\n + document.documentElement.scrollTop\n }\n // posx and posy contain the mouse position relative to the document\n \n const coordinates = { \"x\": posx, \"y\": posy }\n \n return coordinates\n \n }\n \n \n static getElementPositionInDocument(el: { tagName: string; offsetLeft: number; scrollLeft: number; clientLeft: number; offsetTop: number; scrollTop: number; clientTop: number; offsetParent: any }) {\n //https://www.kirupa.com/html5/getting_mouse_click_position.htm\n var xPosition = 0\n var yPosition = 0\n \n while (el) {\n if (el.tagName == \"BODY\") {\n \n // Coordinates in document are coordinates in body, therefore subtracting the scroll position of the body is not needed\n \n // // deal with browser quirks with body/window/document and page scroll\n // var xScrollPos = el.scrollLeft || document.documentElement.scrollLeft;\n // var yScrollPos = el.scrollTop || document.documentElement.scrollTop;\n //\n // xPosition += (el.offsetLeft - xScrollPos + el.clientLeft);\n // yPosition += (el.offsetTop - yScrollPos + el.clientTop);\n }\n else {\n xPosition += (el.offsetLeft - el.scrollLeft + el.clientLeft)\n yPosition += (el.offsetTop - el.scrollTop + el.clientTop)\n }\n \n el = el.offsetParent\n }\n return {\n x: xPosition,\n y: yPosition\n }\n }\n \n static convertCoordinatesFromDocumentToElement(x: number, y: number, element: any) {\n const elementPositionInDocument = this.getElementPositionInDocument(element)\n const coordinatesInElement = { \"x\": x - elementPositionInDocument.x, \"y\": y - elementPositionInDocument.y }\n return coordinatesInElement\n }\n \n static getEventCoordinatesInElement(touchOrMouseEvent: any, element: any) {\n const coordinatesInDocument = this.getEventCoordinatesInDocument(touchOrMouseEvent)\n const coordinatesInElement = this.convertCoordinatesFromDocumentToElement(\n coordinatesInDocument.x,\n coordinatesInDocument.y,\n element\n )\n return coordinatesInElement\n }\n \n \n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAwB;AACxB,sBAAiC;AACjC,oBAA6C;AAGtC,MAAM,
|
|
4
|
+
"sourcesContent": ["import { UIColor } from \"./UIColor\"\nimport { IS, nil, NO, YES } from \"./UIObject\"\nimport { UIView, UIViewBroadcastEvent } from \"./UIView\"\n\n\nexport class UIBaseButton extends UIView {\n \n static override controlEvent = Object.assign({}, UIView.controlEvent, {\n \"PrimaryActionTriggered\": \"PrimaryActionTriggered\"\n } as const)\n \n override controlEvent = UIBaseButton.controlEvent\n \n \n _selected: boolean = NO\n _highlighted: boolean = NO\n \n override _isPointerInside: boolean\n \n \n _isToggleable: boolean = NO\n _hovered?: boolean\n _focused?: boolean\n \n \n constructor(elementID?: string, elementType?: string) {\n \n super(elementID, undefined, elementType)\n \n // Instance variables\n \n \n this._isPointerInside = NO\n \n \n const setHovered = () => {\n this.hovered = YES\n }\n this.addTargetForControlEvent(UIView.controlEvent.PointerHover, setHovered)\n \n const setNotHovered = () => {\n \n this.hovered = NO\n \n }\n \n this.addTargetForControlEvents([\n UIView.controlEvent.PointerLeave, UIView.controlEvent.PointerCancel, UIView.controlEvent.MultipleTouches\n ], setNotHovered)\n \n \n let highlightingTime: number\n const setHighlighted = () => {\n this.highlighted = YES\n highlightingTime = Date.now()\n }\n this.addTargetForControlEvent(UIView.controlEvent.PointerDown, setHighlighted)\n this.addTargetForControlEvent(UIView.controlEvent.PointerEnter, setHighlighted)\n \n const setNotHighlighted = () => {\n this.highlighted = NO\n }\n const setNotHighlightedWithMinimumDuration = () => {\n const minimumDurationInMilliseconds = 50\n const elapsedTime = Date.now() - highlightingTime\n if (minimumDurationInMilliseconds < elapsedTime) {\n this.highlighted = NO\n }\n else {\n setTimeout(() => {\n this.highlighted = NO\n }, minimumDurationInMilliseconds - elapsedTime)\n }\n }\n this.addTargetForControlEvents([\n UIView.controlEvent.PointerLeave, UIView.controlEvent.PointerCancel, UIView.controlEvent.MultipleTouches\n ], setNotHighlighted)\n this.addTargetForControlEvent(UIView.controlEvent.PointerUp, setNotHighlightedWithMinimumDuration)\n \n // Enter and Space both activate the button \u2014 fire PrimaryActionTriggered\n this.addTargetForControlEvent(UIView.controlEvent.EnterDown, () => {\n \n setHighlighted()\n setNotHighlightedWithMinimumDuration()\n this.sendControlEventForKey(UIBaseButton.controlEvent.PrimaryActionTriggered, nil)\n \n })\n \n this.addTargetForControlEvent(UIView.controlEvent.SpaceDown, (sender, event) => {\n \n event.preventDefault()\n setHighlighted()\n setNotHighlightedWithMinimumDuration()\n this.sendControlEventForKey(UIBaseButton.controlEvent.PrimaryActionTriggered, nil)\n \n })\n \n \n this.addTargetForControlEvent(\n UIView.controlEvent.Focus,\n (sender: UIView, event: Event) => {\n \n this.focused = YES\n \n }\n )\n \n this.addTargetForControlEvent(\n UIView.controlEvent.Blur,\n (sender: UIView, event: Event) => {\n \n this.focused = NO\n \n }\n )\n \n \n this.pausesPointerEvents = YES\n this.tabIndex = 1\n \n this.style.cursor = \"pointer\"\n \n //this.style.outline = \"none\";\n \n \n this.nativeSelectionEnabled = NO\n \n \n this.addTargetForControlEvents([\n UIBaseButton.controlEvent.PrimaryActionTriggered, UIView.controlEvent.PointerUpInside\n ], () => {\n \n if (this.isToggleable) {\n \n this.toggleSelectedState()\n \n }\n \n })\n \n }\n \n public set hovered(hovered: boolean) {\n this._hovered = hovered\n this.updateContentForCurrentState()\n }\n \n public get hovered(): boolean {\n return this._hovered ?? NO\n }\n \n public set highlighted(highlighted: boolean) {\n this._highlighted = highlighted\n this.updateContentForCurrentState()\n }\n \n public get highlighted(): boolean {\n return this._highlighted\n }\n \n public set focused(focused: boolean) {\n this._focused = focused\n if (focused) {\n this.focus()\n }\n else {\n this.blur()\n }\n this.updateContentForCurrentState()\n }\n \n public get focused(): boolean {\n return this._focused ?? NO\n }\n \n public set selected(selected: boolean) {\n this._selected = selected\n this.updateContentForCurrentState()\n }\n \n public get selected(): boolean {\n return this._selected\n }\n \n \n updateContentForCurrentState() {\n \n let updateFunction: Function = this.updateContentForNormalState\n if (this.selected && this.highlighted) {\n updateFunction = this.updateContentForSelectedAndHighlightedState\n }\n else if (this.selected) {\n updateFunction = this.updateContentForSelectedState\n }\n else if (this.focused) {\n updateFunction = this.updateContentForFocusedState\n }\n else if (this.highlighted) {\n updateFunction = this.updateContentForHighlightedState\n }\n else if (this.hovered) {\n updateFunction = this.updateContentForHoveredState\n }\n \n if (!IS(updateFunction)) {\n this.backgroundColor = UIColor.nilColor\n }\n else {\n updateFunction.call(this)\n }\n \n }\n \n updateContentForNormalState() {\n \n \n }\n \n updateContentForHoveredState() {\n \n this.updateContentForNormalState()\n \n }\n \n updateContentForFocusedState() {\n \n this.updateContentForHoveredState()\n \n }\n \n updateContentForHighlightedState() {\n \n \n }\n \n updateContentForSelectedState() {\n \n \n }\n \n updateContentForSelectedAndHighlightedState() {\n \n this.updateContentForSelectedState()\n \n }\n \n \n override set enabled(enabled: boolean) {\n super.enabled = enabled\n this.updateContentForCurrentEnabledState()\n }\n \n override get enabled() {\n return super.enabled\n }\n \n override updateContentForCurrentEnabledState() {\n \n if (this.enabled) {\n this.alpha = 1\n }\n else {\n this.alpha = 0.5\n }\n \n this.userInteractionEnabled = this.enabled\n \n }\n \n \n override addStyleClass(styleClassName: string) {\n \n super.addStyleClass(styleClassName)\n \n if (this.styleClassName != styleClassName) {\n \n this.updateContentForCurrentState.call(this)\n \n }\n \n }\n \n \n override didReceiveBroadcastEvent(event: UIViewBroadcastEvent) {\n \n super.didReceiveBroadcastEvent(event)\n \n if (event.name == UIView.broadcastEventName.PageDidScroll || event.name ==\n UIView.broadcastEventName.AddedToViewTree) {\n \n const wasHovered = this._hovered\n const wasHighlighted = this._highlighted\n \n this._hovered = NO\n this._highlighted = NO\n \n if (wasHovered || wasHighlighted) {\n this.updateContentForCurrentState()\n }\n \n }\n \n \n }\n \n \n toggleSelectedState() {\n \n \n this.selected = !this.selected\n \n \n }\n \n set isToggleable(isToggleable: boolean) {\n \n this._isToggleable = isToggleable\n \n }\n \n get isToggleable() {\n \n return this._isToggleable\n \n }\n \n \n override layoutSubviews() {\n \n super.layoutSubviews()\n \n const bounds = this.bounds\n \n \n }\n \n \n override sendControlEventForKey(eventKey: string, nativeEvent: Event) {\n \n if (eventKey == UIView.controlEvent.PointerUpInside && !this.highlighted) {\n \n // Do not send the event in this case\n //super.sendControlEventForKey(eventKey, nativeEvent);\n \n const asd = 1\n \n }\n else {\n \n super.sendControlEventForKey(eventKey, nativeEvent)\n \n if (eventKey == UIView.controlEvent.PointerUpInside) {\n super.sendControlEventForKey(UIBaseButton.controlEvent.PrimaryActionTriggered, nativeEvent)\n }\n \n }\n \n }\n \n \n static getEventCoordinatesInDocument(touchOrMouseEvent: any) {\n // http://www.quirksmode.org/js/events_properties.html\n var posx = 0\n var posy = 0\n var e = touchOrMouseEvent\n if (!e) {\n e = window.event\n }\n if (e.pageX || e.pageY) {\n posx = e.pageX\n posy = e.pageY\n }\n else if (e.clientX || e.clientY) {\n posx = e.clientX + document.body.scrollLeft\n + document.documentElement.scrollLeft\n posy = e.clientY + document.body.scrollTop\n + document.documentElement.scrollTop\n }\n // posx and posy contain the mouse position relative to the document\n \n const coordinates = { \"x\": posx, \"y\": posy }\n \n return coordinates\n \n }\n \n \n static getElementPositionInDocument(el: { tagName: string; offsetLeft: number; scrollLeft: number; clientLeft: number; offsetTop: number; scrollTop: number; clientTop: number; offsetParent: any }) {\n //https://www.kirupa.com/html5/getting_mouse_click_position.htm\n var xPosition = 0\n var yPosition = 0\n \n while (el) {\n if (el.tagName == \"BODY\") {\n \n // Coordinates in document are coordinates in body, therefore subtracting the scroll position of the body is not needed\n \n // // deal with browser quirks with body/window/document and page scroll\n // var xScrollPos = el.scrollLeft || document.documentElement.scrollLeft;\n // var yScrollPos = el.scrollTop || document.documentElement.scrollTop;\n //\n // xPosition += (el.offsetLeft - xScrollPos + el.clientLeft);\n // yPosition += (el.offsetTop - yScrollPos + el.clientTop);\n }\n else {\n xPosition += (el.offsetLeft - el.scrollLeft + el.clientLeft)\n yPosition += (el.offsetTop - el.scrollTop + el.clientTop)\n }\n \n el = el.offsetParent\n }\n return {\n x: xPosition,\n y: yPosition\n }\n }\n \n static convertCoordinatesFromDocumentToElement(x: number, y: number, element: any) {\n const elementPositionInDocument = this.getElementPositionInDocument(element)\n const coordinatesInElement = { \"x\": x - elementPositionInDocument.x, \"y\": y - elementPositionInDocument.y }\n return coordinatesInElement\n }\n \n static getEventCoordinatesInElement(touchOrMouseEvent: any, element: any) {\n const coordinatesInDocument = this.getEventCoordinatesInDocument(touchOrMouseEvent)\n const coordinatesInElement = this.convertCoordinatesFromDocumentToElement(\n coordinatesInDocument.x,\n coordinatesInDocument.y,\n element\n )\n return coordinatesInElement\n }\n \n \n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -15,6 +15,7 @@ export declare class UIDateTimeInput extends UIView {
|
|
|
15
15
|
readonly PointerHover: "PointerHover";
|
|
16
16
|
readonly EnterDown: "EnterDown";
|
|
17
17
|
readonly EnterUp: "EnterUp";
|
|
18
|
+
readonly SpaceDown: "SpaceDown";
|
|
18
19
|
readonly EscDown: "EscDown";
|
|
19
20
|
readonly TabDown: "TabDown";
|
|
20
21
|
readonly LeftArrowDown: "LeftArrowDown";
|
|
@@ -35,6 +35,7 @@ export declare class UITextField extends UITextView {
|
|
|
35
35
|
readonly PointerHover: "PointerHover";
|
|
36
36
|
readonly EnterDown: "EnterDown";
|
|
37
37
|
readonly EnterUp: "EnterUp";
|
|
38
|
+
readonly SpaceDown: "SpaceDown";
|
|
38
39
|
readonly EscDown: "EscDown";
|
|
39
40
|
readonly TabDown: "TabDown";
|
|
40
41
|
readonly LeftArrowDown: "LeftArrowDown";
|
|
@@ -451,6 +451,7 @@ export declare class UIView extends UIObject {
|
|
|
451
451
|
readonly PointerHover: "PointerHover";
|
|
452
452
|
readonly EnterDown: "EnterDown";
|
|
453
453
|
readonly EnterUp: "EnterUp";
|
|
454
|
+
readonly SpaceDown: "SpaceDown";
|
|
454
455
|
readonly EscDown: "EscDown";
|
|
455
456
|
readonly TabDown: "TabDown";
|
|
456
457
|
readonly LeftArrowDown: "LeftArrowDown";
|
|
@@ -474,6 +475,7 @@ export declare class UIView extends UIObject {
|
|
|
474
475
|
readonly PointerHover: "PointerHover";
|
|
475
476
|
readonly EnterDown: "EnterDown";
|
|
476
477
|
readonly EnterUp: "EnterUp";
|
|
478
|
+
readonly SpaceDown: "SpaceDown";
|
|
477
479
|
readonly EscDown: "EscDown";
|
|
478
480
|
readonly TabDown: "TabDown";
|
|
479
481
|
readonly LeftArrowDown: "LeftArrowDown";
|
|
@@ -2299,20 +2299,17 @@ const _UIView = class extends import_UIObject.UIObject {
|
|
|
2299
2299
|
return import_UIObject.YES;
|
|
2300
2300
|
}
|
|
2301
2301
|
const onKeyDown = (event) => {
|
|
2302
|
-
if (eventKeyIsEnter(event)
|
|
2302
|
+
if (eventKeyIsEnter(event)) {
|
|
2303
2303
|
this.sendControlEventForKey(_UIView.controlEvent.EnterDown, event);
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
pauseEvent(event, import_UIObject.YES);
|
|
2308
|
-
}
|
|
2304
|
+
}
|
|
2305
|
+
if (eventKeyIsSpace(event)) {
|
|
2306
|
+
this.sendControlEventForKey(_UIView.controlEvent.SpaceDown, event);
|
|
2309
2307
|
}
|
|
2310
2308
|
if (eventKeyIsEsc(event)) {
|
|
2311
2309
|
this.sendControlEventForKey(_UIView.controlEvent.EscDown, event);
|
|
2312
2310
|
}
|
|
2313
|
-
if (eventKeyIsTab(event)
|
|
2311
|
+
if (eventKeyIsTab(event)) {
|
|
2314
2312
|
this.sendControlEventForKey(_UIView.controlEvent.TabDown, event);
|
|
2315
|
-
pauseEvent(event, import_UIObject.YES);
|
|
2316
2313
|
}
|
|
2317
2314
|
if (eventKeyIsLeft(event)) {
|
|
2318
2315
|
this.sendControlEventForKey(_UIView.controlEvent.LeftArrowDown, event);
|
|
@@ -2326,6 +2323,9 @@ const _UIView = class extends import_UIObject.UIObject {
|
|
|
2326
2323
|
if (eventKeyIsUp(event)) {
|
|
2327
2324
|
this.sendControlEventForKey(_UIView.controlEvent.UpArrowDown, event);
|
|
2328
2325
|
}
|
|
2326
|
+
if (event.defaultPrevented) {
|
|
2327
|
+
pauseEvent(event, import_UIObject.YES);
|
|
2328
|
+
}
|
|
2329
2329
|
};
|
|
2330
2330
|
const onKeyUp = (event) => {
|
|
2331
2331
|
if (eventKeyIsEnter(event)) {
|
|
@@ -2824,6 +2824,7 @@ UIView.controlEvent = {
|
|
|
2824
2824
|
"PointerHover": "PointerHover",
|
|
2825
2825
|
"EnterDown": "EnterDown",
|
|
2826
2826
|
"EnterUp": "EnterUp",
|
|
2827
|
+
"SpaceDown": "SpaceDown",
|
|
2827
2828
|
"EscDown": "EscDown",
|
|
2828
2829
|
"TabDown": "TabDown",
|
|
2829
2830
|
"LeftArrowDown": "LeftArrowDown",
|