@liwe3/webcomponents 1.0.0 → 1.0.2
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/dist/SmartSelect.js +3 -0
- package/dist/SmartSelect.js.map +1 -1
- package/package.json +2 -2
- package/src/SmartSelect.ts +3 -0
package/dist/SmartSelect.js
CHANGED
|
@@ -294,6 +294,7 @@ class g extends HTMLElement {
|
|
|
294
294
|
min-height: 36px;
|
|
295
295
|
box-sizing: border-box;
|
|
296
296
|
color: #333;
|
|
297
|
+
user-select: none;
|
|
297
298
|
}
|
|
298
299
|
|
|
299
300
|
.select-trigger:focus {
|
|
@@ -323,6 +324,7 @@ class g extends HTMLElement {
|
|
|
323
324
|
border-radius: var(--tag-border-radius, 12px);
|
|
324
325
|
font-size: 12px;
|
|
325
326
|
color: var(--tag-color, #495057);
|
|
327
|
+
user-select: none;
|
|
326
328
|
}
|
|
327
329
|
|
|
328
330
|
.remove-tag {
|
|
@@ -377,6 +379,7 @@ class g extends HTMLElement {
|
|
|
377
379
|
cursor: pointer;
|
|
378
380
|
color: var(--option-color, #333);
|
|
379
381
|
transition: background-color 0.2s;
|
|
382
|
+
user-select: none;
|
|
380
383
|
}
|
|
381
384
|
|
|
382
385
|
.option:hover {
|
package/dist/SmartSelect.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SmartSelect.js","sources":["../src/SmartSelect.ts"],"sourcesContent":["/**\n * SmartSelect Web Component\n * A customizable select dropdown with search, multi-select, and keyboard navigation\n */\n\nexport interface SelectOption {\n value: string;\n label: string;\n}\n\nexport class SmartSelectElement extends HTMLElement {\n declare shadowRoot: ShadowRoot;\n private isOpen: boolean = false;\n private selectedOptions: SelectOption[] = [];\n private filteredOptions: SelectOption[] = [];\n private focusedIndex: number = -1;\n private searchValue: string = '';\n private keyboardNavigating: boolean = false;\n private keyboardTimer?: number;\n\n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n\n // Make component focusable\n if (!this.hasAttribute('tabindex')) {\n this.setAttribute('tabindex', '0');\n }\n\n this.render();\n this.bindEvents();\n }\n\n static get observedAttributes(): string[] {\n return ['multiple', 'searchable', 'placeholder', 'disabled', 'value', 'options'];\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue !== newValue) {\n if (name === 'options') {\n this.filteredOptions = [...this.options];\n }\n this.render();\n }\n }\n\n get multiple(): boolean {\n return this.hasAttribute('multiple');\n }\n\n set multiple(value: boolean) {\n if (value) {\n this.setAttribute('multiple', '');\n } else {\n this.removeAttribute('multiple');\n }\n }\n\n get searchable(): boolean {\n return this.hasAttribute('searchable');\n }\n\n set searchable(value: boolean) {\n if (value) {\n this.setAttribute('searchable', '');\n } else {\n this.removeAttribute('searchable');\n }\n }\n\n get placeholder(): string {\n return this.getAttribute('placeholder') || 'Select an option';\n }\n\n set placeholder(value: string) {\n this.setAttribute('placeholder', value);\n }\n\n get disabled(): boolean {\n return this.hasAttribute('disabled');\n }\n\n set disabled(value: boolean) {\n if (value) {\n this.setAttribute('disabled', '');\n } else {\n this.removeAttribute('disabled');\n }\n }\n\n get value(): string | string[] {\n if (this.multiple) {\n return this.selectedOptions.map(opt => opt.value);\n }\n return this.selectedOptions.length > 0 ? this.selectedOptions[0].value : '';\n }\n\n set value(val: string | string[]) {\n if (this.multiple && Array.isArray(val)) {\n this.selectedOptions = this.options.filter(opt => val.includes(opt.value));\n } else {\n const option = this.options.find(opt => opt.value === val);\n this.selectedOptions = option ? [option] : [];\n }\n this.render();\n }\n\n get options(): SelectOption[] {\n const optionsAttr = this.getAttribute('options');\n if (optionsAttr) {\n try {\n return JSON.parse(optionsAttr);\n } catch (e) {\n console.error('Invalid options format:', e);\n return [];\n }\n }\n return [];\n }\n\n set options(opts: SelectOption[]) {\n this.setAttribute('options', JSON.stringify(opts));\n }\n\n /**\n * Opens the dropdown\n */\n open(): void {\n if (this.disabled) return;\n this.isOpen = true;\n this.focusedIndex = -1;\n if (this.options.length > 0) {\n this.filteredOptions = [...this.options];\n }\n this.render();\n\n // Update dropdown position based on viewport\n this._updateDropdownPosition();\n\n // Focus search input if searchable\n if (this.searchable) {\n requestAnimationFrame(() => {\n const searchInput = this.shadowRoot.querySelector('.search-input') as HTMLInputElement;\n if (searchInput) {\n searchInput.focus();\n }\n });\n }\n\n this.dispatchEvent(new CustomEvent('open'));\n }\n\n /**\n * Closes the dropdown\n */\n close(): void {\n this.isOpen = false;\n this.focusedIndex = -1;\n this.searchValue = '';\n\n // Reset filtered options when closing\n if (this.searchable && this.options.length > 0) {\n this.filteredOptions = [...this.options];\n }\n\n // Clear any inline positioning styles\n const dropdown = this.shadowRoot.querySelector('.dropdown') as HTMLElement;\n if (dropdown) {\n dropdown.style.top = '';\n dropdown.style.left = '';\n dropdown.style.width = '';\n dropdown.style.maxHeight = '';\n }\n\n this.render();\n this.dispatchEvent(new CustomEvent('close'));\n }\n\n /**\n * Toggles the dropdown open/closed state\n */\n toggle(): void {\n if (this.isOpen) {\n this.close();\n } else {\n this.open();\n }\n }\n\n /**\n * Selects an option by its value\n */\n selectOption(value: string): void {\n const option = this.options.find(opt => opt.value === value);\n if (!option) return;\n\n if (this.multiple) {\n if (!this.selectedOptions.find(opt => opt.value === value)) {\n this.selectedOptions.push(option);\n }\n } else {\n this.selectedOptions = [option];\n this.close();\n }\n\n this.render();\n this.dispatchEvent(new CustomEvent('change', { detail: { value: this.value } }));\n }\n\n /**\n * Deselects an option by its value\n */\n deselectOption(value: string): void {\n this.selectedOptions = this.selectedOptions.filter(opt => opt.value !== value);\n this.render();\n this.dispatchEvent(new CustomEvent('change', { detail: { value: this.value } }));\n }\n\n /**\n * Returns an array of currently selected options\n */\n getSelectedOptions(): SelectOption[] {\n return [...this.selectedOptions];\n }\n\n /**\n * Sets the options for the select component\n */\n setOptions(options: SelectOption[]): void {\n this.options = options;\n this.filteredOptions = [...options];\n this.selectedOptions = [];\n this.render();\n }\n\n /**\n * Handles search functionality\n */\n private handleSearch(query: string): void {\n this.searchValue = query;\n this.filteredOptions = this.options.filter(option =>\n option.label.toLowerCase().includes(query.toLowerCase())\n );\n this.focusedIndex = -1;\n this.render();\n this.dispatchEvent(new CustomEvent('search', { detail: { query } }));\n }\n\n /**\n * Updates the visual focus state without full re-render\n */\n private updateFocusedOption(): void {\n const options = this.shadowRoot.querySelectorAll('.option');\n\n // Remove focused class from all options\n options.forEach(option => option.classList.remove('focused'));\n\n // Add focused class to current option\n if (this.focusedIndex >= 0 && this.focusedIndex < options.length) {\n options[this.focusedIndex].classList.add('focused');\n }\n\n this.scrollToFocusedOption();\n }\n\n /**\n * Scrolls the focused option into view\n */\n private scrollToFocusedOption(): void {\n if (this.focusedIndex < 0) return;\n\n requestAnimationFrame(() => {\n const dropdown = this.shadowRoot.querySelector('.dropdown') as HTMLElement;\n const focusedOption = this.shadowRoot.querySelector('.option.focused') as HTMLElement;\n\n if (dropdown && focusedOption) {\n const dropdownRect = dropdown.getBoundingClientRect();\n const optionRect = focusedOption.getBoundingClientRect();\n\n // Check if option is above visible area\n if (optionRect.top < dropdownRect.top) {\n dropdown.scrollTop -= (dropdownRect.top - optionRect.top);\n }\n // Check if option is below visible area\n else if (optionRect.bottom > dropdownRect.bottom) {\n dropdown.scrollTop += (optionRect.bottom - dropdownRect.bottom);\n }\n }\n });\n }\n\n /**\n * Calculates the optimal dropdown position based on viewport constraints\n */\n private _calculateDropdownPosition(): { top: number; left: number; width: number; maxHeight: number } | null {\n const trigger = this.shadowRoot.querySelector('.select-trigger') as HTMLElement;\n if (!trigger) return null;\n\n const triggerRect = trigger.getBoundingClientRect();\n const viewportHeight = window.innerHeight;\n const viewportWidth = window.innerWidth;\n const dropdownMaxHeight = 200;\n const dropdownPadding = 10;\n const margin = 2;\n\n // Calculate available space\n const spaceBelow = viewportHeight - triggerRect.bottom;\n const spaceAbove = triggerRect.top;\n\n // Determine if dropdown should open upward\n const shouldOpenUpward = spaceBelow < dropdownMaxHeight + dropdownPadding && spaceAbove > spaceBelow;\n\n // Calculate dimensions\n const width = triggerRect.width;\n const left = Math.max(0, Math.min(triggerRect.left, viewportWidth - width));\n\n let top: number;\n let maxHeight: number;\n\n if (shouldOpenUpward) {\n // Position above the trigger\n maxHeight = Math.min(dropdownMaxHeight, spaceAbove - dropdownPadding);\n top = triggerRect.top - maxHeight - margin;\n } else {\n // Position below the trigger\n maxHeight = Math.min(dropdownMaxHeight, spaceBelow - dropdownPadding);\n top = triggerRect.bottom + margin;\n }\n\n return {\n top: Math.max(0, top),\n left,\n width,\n maxHeight: Math.max(100, maxHeight) // Ensure minimum height\n };\n }\n\n /**\n * Updates dropdown position using fixed positioning relative to viewport\n */\n private _updateDropdownPosition(): void {\n requestAnimationFrame(() => {\n const dropdown = this.shadowRoot.querySelector('.dropdown') as HTMLElement;\n if (!dropdown) return;\n\n const position = this._calculateDropdownPosition();\n if (!position) return;\n\n // Apply calculated position as inline styles\n dropdown.style.top = `${position.top}px`;\n dropdown.style.left = `${position.left}px`;\n dropdown.style.width = `${position.width}px`;\n dropdown.style.maxHeight = `${position.maxHeight}px`;\n });\n }\n\n /**\n * Handles keyboard navigation\n */\n private handleKeydown(event: KeyboardEvent): void {\n if (this.disabled) return;\n\n // Prevent double execution if event has already been handled\n if ((event as any)._smartSelectHandled) return;\n (event as any)._smartSelectHandled = true;\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n this.keyboardNavigating = true;\n clearTimeout(this.keyboardTimer);\n this.keyboardTimer = window.setTimeout(() => { this.keyboardNavigating = false; }, 100);\n\n if (!this.isOpen) {\n this.open();\n } else {\n // If searchable and search input is focused, move to first option\n const searchInput = this.shadowRoot.querySelector('.search-input') as HTMLInputElement;\n const isSearchFocused = this.searchable && searchInput === this.shadowRoot.activeElement;\n\n if (isSearchFocused) {\n this.focusedIndex = 0;\n searchInput.blur(); // Blur search input to allow normal navigation\n // Focus the component to ensure it receives keyboard events\n this.focus();\n this.updateFocusedOption();\n return;\n }\n // Navigate through options\n const newIndex = Math.min(this.focusedIndex + 1, this.filteredOptions.length - 1);\n this.focusedIndex = newIndex;\n this.updateFocusedOption();\n }\n break;\n\n case 'ArrowUp':\n event.preventDefault();\n this.keyboardNavigating = true;\n clearTimeout(this.keyboardTimer);\n this.keyboardTimer = window.setTimeout(() => { this.keyboardNavigating = false; }, 100);\n\n if (this.isOpen) {\n // If at first option and searchable, focus search input\n if (this.focusedIndex === 0 && this.searchable) {\n this.focusedIndex = -1;\n this.updateFocusedOption();\n requestAnimationFrame(() => {\n const searchInput = this.shadowRoot.querySelector('.search-input') as HTMLInputElement;\n if (searchInput) {\n searchInput.focus();\n searchInput.setSelectionRange(searchInput.value.length, searchInput.value.length);\n }\n });\n return;\n }\n // If searchable and search input is focused, do nothing\n const searchInput = this.shadowRoot.querySelector('.search-input') as HTMLInputElement;\n const isSearchFocused = this.searchable && searchInput === this.shadowRoot.activeElement;\n\n if (isSearchFocused) {\n return;\n }\n // Navigate through options\n const newIndex = Math.max(this.focusedIndex - 1, -1);\n this.focusedIndex = newIndex;\n this.updateFocusedOption();\n }\n break;\n\n case 'Enter':\n event.preventDefault();\n if (this.isOpen && this.focusedIndex >= 0 && this.focusedIndex < this.filteredOptions.length) {\n this.selectOption(this.filteredOptions[this.focusedIndex].value);\n } else if (!this.isOpen) {\n this.open();\n }\n break;\n\n case 'Escape':\n event.preventDefault();\n this.close();\n break;\n\n case 'Tab':\n this.close();\n break;\n }\n }\n\n /**\n * Binds all event listeners\n */\n private bindEvents(): void {\n // Listen for keydown events on both the component and shadow root\n const keydownHandler = this.handleKeydown.bind(this);\n this.addEventListener('keydown', keydownHandler);\n this.shadowRoot.addEventListener('keydown', keydownHandler as EventListener);\n\n // Use event delegation on the shadow root\n this.shadowRoot.addEventListener('click', (e) => {\n e.stopPropagation();\n const target = e.target as HTMLElement;\n\n if (target.closest('.remove-tag')) {\n const value = (target.closest('.remove-tag') as HTMLElement).dataset.value;\n if (value) this.deselectOption(value);\n } else if (target.closest('.option')) {\n const value = (target.closest('.option') as HTMLElement).dataset.value;\n if (value) this.selectOption(value);\n } else if (target.closest('.select-trigger')) {\n this.toggle();\n }\n });\n\n // Handle mouse hover on options to update focused index\n this.shadowRoot.addEventListener('mouseover', (e) => {\n // Don't interfere with keyboard navigation\n if (this.keyboardNavigating) return;\n\n const target = e.target as HTMLElement;\n if (target.closest('.option')) {\n const option = target.closest('.option') as HTMLElement;\n const options = Array.from(this.shadowRoot.querySelectorAll('.option'));\n const newFocusedIndex = options.indexOf(option);\n\n // Only update if the focused index actually changed\n if (this.focusedIndex !== newFocusedIndex) {\n // Remove focused class from current option\n const currentFocused = this.shadowRoot.querySelector('.option.focused');\n if (currentFocused) {\n currentFocused.classList.remove('focused');\n }\n\n // Add focused class to new option\n option.classList.add('focused');\n this.focusedIndex = newFocusedIndex;\n }\n }\n });\n\n // Handle mouse leaving dropdown to clear focus\n this.shadowRoot.addEventListener('mouseleave', (e) => {\n // Don't interfere with keyboard navigation\n if (this.keyboardNavigating) return;\n\n const target = e.target as HTMLElement;\n if (target.closest('.dropdown')) {\n const currentFocused = this.shadowRoot.querySelector('.option.focused');\n if (currentFocused) {\n currentFocused.classList.remove('focused');\n }\n this.focusedIndex = -1;\n }\n });\n\n // Handle search input\n this.shadowRoot.addEventListener('input', (e) => {\n const target = e.target as HTMLInputElement;\n if (target.classList.contains('search-input')) {\n this.handleSearch(target.value);\n }\n });\n\n // Close dropdown when clicking outside\n document.addEventListener('click', (e) => {\n if (!this.contains(e.target as Node)) {\n this.close();\n }\n });\n\n // Update dropdown position on window resize or scroll\n window.addEventListener('resize', () => {\n if (this.isOpen) {\n this._updateDropdownPosition();\n }\n });\n\n window.addEventListener('scroll', () => {\n if (this.isOpen) {\n this._updateDropdownPosition();\n }\n }, true); // Use capture to catch all scroll events\n }\n\n /**\n * Renders the component\n */\n private render(): void {\n // Initialize filteredOptions if not set\n if (this.filteredOptions.length === 0 && this.options.length > 0) {\n this.filteredOptions = [...this.options];\n }\n\n // Remember if search input was focused before render\n const wasSearchFocused = this.shadowRoot.querySelector('.search-input') === this.shadowRoot.activeElement;\n\n const displayText = this.selectedOptions.length > 0\n ? (this.multiple\n ? `${this.selectedOptions.length} selected`\n : this.selectedOptions[0].label)\n : this.placeholder;\n\n this.shadowRoot.innerHTML = `\n <style>\n :host {\n display: inline-block;\n position: relative;\n min-width: 200px;\n font-family: var(--font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);\n font-size: var(--font-size, 14px);\n outline: none;\n }\n\n :host(:focus) .select-trigger {\n border-color: var(--focus-color, #007bff);\n box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);\n }\n\n :host([disabled]) {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .select-container {\n position: relative;\n }\n\n .select-trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--padding, 8px 12px);\n border: var(--border, 1px solid #ccc);\n border-radius: var(--border-radius, 4px);\n background: var(--background, white);\n cursor: pointer;\n min-height: 36px;\n box-sizing: border-box;\n color: #333;\n }\n\n .select-trigger:focus {\n outline: none;\n border-color: var(--focus-color, #007bff);\n box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);\n }\n\n .select-trigger[disabled] {\n cursor: not-allowed;\n }\n\n .selected-content {\n display: flex;\n align-items: center;\n gap: 4px;\n flex-wrap: wrap;\n flex: 1;\n }\n\n .tag {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 8px;\n background: var(--tag-background, #e9ecef);\n border-radius: var(--tag-border-radius, 12px);\n font-size: 12px;\n color: var(--tag-color, #495057);\n }\n\n .remove-tag {\n cursor: pointer;\n color: var(--remove-color, #6c757d);\n font-weight: bold;\n font-size: 14px;\n }\n\n .remove-tag:hover {\n color: var(--remove-hover-color, #dc3545);\n }\n\n .arrow {\n width: 0;\n height: 0;\n border-left: 5px solid transparent;\n border-right: 5px solid transparent;\n border-top: 5px solid var(--arrow-color, #666);\n transition: transform 0.2s;\n }\n\n .arrow.open {\n transform: rotate(180deg);\n }\n\n .dropdown {\n position: fixed;\n z-index: 99999;\n background: var(--dropdown-background, white);\n border: var(--dropdown-border, 1px solid #ccc);\n border-radius: var(--dropdown-border-radius, 4px);\n box-shadow: var(--dropdown-shadow, 0 2px 8px rgba(0, 0, 0, 0.1));\n max-height: 200px;\n overflow-y: auto;\n scroll-behavior: smooth;\n color: #333;\n }\n\n .search-input {\n width: 100%;\n padding: 8px 12px;\n border: none;\n border-bottom: 1px solid #eee;\n font-size: 14px;\n outline: none;\n box-sizing: border-box;\n }\n\n .option {\n padding: 8px 12px;\n cursor: pointer;\n color: var(--option-color, #333);\n transition: background-color 0.2s;\n }\n\n .option:hover {\n background-color: var(--option-hover-background, #f8f9fa);\n }\n\n .option.focused {\n background-color: var(--option-focused-background, #007bff);\n color: var(--option-focused-color, white);\n }\n\n .option.selected {\n background-color: var(--option-selected-background, #e3f2fd);\n color: var(--option-selected-color, #1976d2);\n }\n\n .no-options {\n padding: 8px 12px;\n color: var(--no-options-color, #6c757d);\n font-style: italic;\n }\n </style>\n\n <div class=\"select-container\">\n <div class=\"select-trigger\" tabindex=\"-1\">\n <div class=\"selected-content\">\n ${this.multiple && this.selectedOptions.length > 0\n ? this.selectedOptions.map(option => `\n <span class=\"tag\">\n ${option.label}\n <span class=\"remove-tag\" data-value=\"${option.value}\">×</span>\n </span>\n `).join('')\n : `<span>${displayText}</span>`\n }\n </div>\n <div class=\"arrow ${this.isOpen ? 'open' : ''}\"></div>\n </div>\n\n ${this.isOpen ? `\n <div class=\"dropdown\">\n ${this.searchable ? `\n <input\n type=\"text\"\n class=\"search-input\"\n placeholder=\"Search options...\"\n value=\"${this.searchValue}\"\n >\n ` : ''}\n\n ${this.filteredOptions.length > 0\n ? this.filteredOptions.map((option, index) => `\n <div\n class=\"option ${this.selectedOptions.find(selected => selected.value === option.value) ? 'selected' : ''} ${index === this.focusedIndex ? 'focused' : ''}\"\n data-value=\"${option.value}\"\n >\n ${option.label}\n </div>\n `).join('')\n : '<div class=\"no-options\">No options available</div>'\n }\n </div>\n ` : ''}\n </div>\n `;\n\n // Re-focus search input if it was previously focused\n if (wasSearchFocused && this.searchable && this.isOpen) {\n requestAnimationFrame(() => {\n const searchInput = this.shadowRoot.querySelector('.search-input') as HTMLInputElement;\n if (searchInput) {\n searchInput.focus();\n // Restore cursor position to the end\n searchInput.setSelectionRange(searchInput.value.length, searchInput.value.length);\n }\n });\n }\n }\n}\n\n/**\n * Conditionally defines the custom element if in a browser environment.\n */\nconst defineSmartSelect = (tagName: string = 'liwe3-select'): void => {\n if (typeof window !== 'undefined' && !window.customElements.get(tagName)) {\n customElements.define(tagName, SmartSelectElement);\n }\n};\n\n// Auto-register with default tag name\ndefineSmartSelect();\n\nexport { defineSmartSelect };\n"],"names":["SmartSelectElement","name","oldValue","newValue","value","opt","val","option","optionsAttr","e","opts","searchInput","dropdown","options","query","focusedOption","dropdownRect","optionRect","trigger","triggerRect","viewportHeight","viewportWidth","dropdownMaxHeight","dropdownPadding","margin","spaceBelow","spaceAbove","shouldOpenUpward","width","left","top","maxHeight","position","event","newIndex","keydownHandler","target","newFocusedIndex","currentFocused","wasSearchFocused","displayText","index","selected","defineSmartSelect","tagName"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SmartSelect.js","sources":["../src/SmartSelect.ts"],"sourcesContent":["/**\n * SmartSelect Web Component\n * A customizable select dropdown with search, multi-select, and keyboard navigation\n */\n\nexport interface SelectOption {\n value: string;\n label: string;\n}\n\nexport class SmartSelectElement extends HTMLElement {\n declare shadowRoot: ShadowRoot;\n private isOpen: boolean = false;\n private selectedOptions: SelectOption[] = [];\n private filteredOptions: SelectOption[] = [];\n private focusedIndex: number = -1;\n private searchValue: string = '';\n private keyboardNavigating: boolean = false;\n private keyboardTimer?: number;\n\n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n\n // Make component focusable\n if (!this.hasAttribute('tabindex')) {\n this.setAttribute('tabindex', '0');\n }\n\n this.render();\n this.bindEvents();\n }\n\n static get observedAttributes(): string[] {\n return ['multiple', 'searchable', 'placeholder', 'disabled', 'value', 'options'];\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue !== newValue) {\n if (name === 'options') {\n this.filteredOptions = [...this.options];\n }\n this.render();\n }\n }\n\n get multiple(): boolean {\n return this.hasAttribute('multiple');\n }\n\n set multiple(value: boolean) {\n if (value) {\n this.setAttribute('multiple', '');\n } else {\n this.removeAttribute('multiple');\n }\n }\n\n get searchable(): boolean {\n return this.hasAttribute('searchable');\n }\n\n set searchable(value: boolean) {\n if (value) {\n this.setAttribute('searchable', '');\n } else {\n this.removeAttribute('searchable');\n }\n }\n\n get placeholder(): string {\n return this.getAttribute('placeholder') || 'Select an option';\n }\n\n set placeholder(value: string) {\n this.setAttribute('placeholder', value);\n }\n\n get disabled(): boolean {\n return this.hasAttribute('disabled');\n }\n\n set disabled(value: boolean) {\n if (value) {\n this.setAttribute('disabled', '');\n } else {\n this.removeAttribute('disabled');\n }\n }\n\n get value(): string | string[] {\n if (this.multiple) {\n return this.selectedOptions.map(opt => opt.value);\n }\n return this.selectedOptions.length > 0 ? this.selectedOptions[0].value : '';\n }\n\n set value(val: string | string[]) {\n if (this.multiple && Array.isArray(val)) {\n this.selectedOptions = this.options.filter(opt => val.includes(opt.value));\n } else {\n const option = this.options.find(opt => opt.value === val);\n this.selectedOptions = option ? [option] : [];\n }\n this.render();\n }\n\n get options(): SelectOption[] {\n const optionsAttr = this.getAttribute('options');\n if (optionsAttr) {\n try {\n return JSON.parse(optionsAttr);\n } catch (e) {\n console.error('Invalid options format:', e);\n return [];\n }\n }\n return [];\n }\n\n set options(opts: SelectOption[]) {\n this.setAttribute('options', JSON.stringify(opts));\n }\n\n /**\n * Opens the dropdown\n */\n open(): void {\n if (this.disabled) return;\n this.isOpen = true;\n this.focusedIndex = -1;\n if (this.options.length > 0) {\n this.filteredOptions = [...this.options];\n }\n this.render();\n\n // Update dropdown position based on viewport\n this._updateDropdownPosition();\n\n // Focus search input if searchable\n if (this.searchable) {\n requestAnimationFrame(() => {\n const searchInput = this.shadowRoot.querySelector('.search-input') as HTMLInputElement;\n if (searchInput) {\n searchInput.focus();\n }\n });\n }\n\n this.dispatchEvent(new CustomEvent('open'));\n }\n\n /**\n * Closes the dropdown\n */\n close(): void {\n this.isOpen = false;\n this.focusedIndex = -1;\n this.searchValue = '';\n\n // Reset filtered options when closing\n if (this.searchable && this.options.length > 0) {\n this.filteredOptions = [...this.options];\n }\n\n // Clear any inline positioning styles\n const dropdown = this.shadowRoot.querySelector('.dropdown') as HTMLElement;\n if (dropdown) {\n dropdown.style.top = '';\n dropdown.style.left = '';\n dropdown.style.width = '';\n dropdown.style.maxHeight = '';\n }\n\n this.render();\n this.dispatchEvent(new CustomEvent('close'));\n }\n\n /**\n * Toggles the dropdown open/closed state\n */\n toggle(): void {\n if (this.isOpen) {\n this.close();\n } else {\n this.open();\n }\n }\n\n /**\n * Selects an option by its value\n */\n selectOption(value: string): void {\n const option = this.options.find(opt => opt.value === value);\n if (!option) return;\n\n if (this.multiple) {\n if (!this.selectedOptions.find(opt => opt.value === value)) {\n this.selectedOptions.push(option);\n }\n } else {\n this.selectedOptions = [option];\n this.close();\n }\n\n this.render();\n this.dispatchEvent(new CustomEvent('change', { detail: { value: this.value } }));\n }\n\n /**\n * Deselects an option by its value\n */\n deselectOption(value: string): void {\n this.selectedOptions = this.selectedOptions.filter(opt => opt.value !== value);\n this.render();\n this.dispatchEvent(new CustomEvent('change', { detail: { value: this.value } }));\n }\n\n /**\n * Returns an array of currently selected options\n */\n getSelectedOptions(): SelectOption[] {\n return [...this.selectedOptions];\n }\n\n /**\n * Sets the options for the select component\n */\n setOptions(options: SelectOption[]): void {\n this.options = options;\n this.filteredOptions = [...options];\n this.selectedOptions = [];\n this.render();\n }\n\n /**\n * Handles search functionality\n */\n private handleSearch(query: string): void {\n this.searchValue = query;\n this.filteredOptions = this.options.filter(option =>\n option.label.toLowerCase().includes(query.toLowerCase())\n );\n this.focusedIndex = -1;\n this.render();\n this.dispatchEvent(new CustomEvent('search', { detail: { query } }));\n }\n\n /**\n * Updates the visual focus state without full re-render\n */\n private updateFocusedOption(): void {\n const options = this.shadowRoot.querySelectorAll('.option');\n\n // Remove focused class from all options\n options.forEach(option => option.classList.remove('focused'));\n\n // Add focused class to current option\n if (this.focusedIndex >= 0 && this.focusedIndex < options.length) {\n options[this.focusedIndex].classList.add('focused');\n }\n\n this.scrollToFocusedOption();\n }\n\n /**\n * Scrolls the focused option into view\n */\n private scrollToFocusedOption(): void {\n if (this.focusedIndex < 0) return;\n\n requestAnimationFrame(() => {\n const dropdown = this.shadowRoot.querySelector('.dropdown') as HTMLElement;\n const focusedOption = this.shadowRoot.querySelector('.option.focused') as HTMLElement;\n\n if (dropdown && focusedOption) {\n const dropdownRect = dropdown.getBoundingClientRect();\n const optionRect = focusedOption.getBoundingClientRect();\n\n // Check if option is above visible area\n if (optionRect.top < dropdownRect.top) {\n dropdown.scrollTop -= (dropdownRect.top - optionRect.top);\n }\n // Check if option is below visible area\n else if (optionRect.bottom > dropdownRect.bottom) {\n dropdown.scrollTop += (optionRect.bottom - dropdownRect.bottom);\n }\n }\n });\n }\n\n /**\n * Calculates the optimal dropdown position based on viewport constraints\n */\n private _calculateDropdownPosition(): { top: number; left: number; width: number; maxHeight: number } | null {\n const trigger = this.shadowRoot.querySelector('.select-trigger') as HTMLElement;\n if (!trigger) return null;\n\n const triggerRect = trigger.getBoundingClientRect();\n const viewportHeight = window.innerHeight;\n const viewportWidth = window.innerWidth;\n const dropdownMaxHeight = 200;\n const dropdownPadding = 10;\n const margin = 2;\n\n // Calculate available space\n const spaceBelow = viewportHeight - triggerRect.bottom;\n const spaceAbove = triggerRect.top;\n\n // Determine if dropdown should open upward\n const shouldOpenUpward = spaceBelow < dropdownMaxHeight + dropdownPadding && spaceAbove > spaceBelow;\n\n // Calculate dimensions\n const width = triggerRect.width;\n const left = Math.max(0, Math.min(triggerRect.left, viewportWidth - width));\n\n let top: number;\n let maxHeight: number;\n\n if (shouldOpenUpward) {\n // Position above the trigger\n maxHeight = Math.min(dropdownMaxHeight, spaceAbove - dropdownPadding);\n top = triggerRect.top - maxHeight - margin;\n } else {\n // Position below the trigger\n maxHeight = Math.min(dropdownMaxHeight, spaceBelow - dropdownPadding);\n top = triggerRect.bottom + margin;\n }\n\n return {\n top: Math.max(0, top),\n left,\n width,\n maxHeight: Math.max(100, maxHeight) // Ensure minimum height\n };\n }\n\n /**\n * Updates dropdown position using fixed positioning relative to viewport\n */\n private _updateDropdownPosition(): void {\n requestAnimationFrame(() => {\n const dropdown = this.shadowRoot.querySelector('.dropdown') as HTMLElement;\n if (!dropdown) return;\n\n const position = this._calculateDropdownPosition();\n if (!position) return;\n\n // Apply calculated position as inline styles\n dropdown.style.top = `${position.top}px`;\n dropdown.style.left = `${position.left}px`;\n dropdown.style.width = `${position.width}px`;\n dropdown.style.maxHeight = `${position.maxHeight}px`;\n });\n }\n\n /**\n * Handles keyboard navigation\n */\n private handleKeydown(event: KeyboardEvent): void {\n if (this.disabled) return;\n\n // Prevent double execution if event has already been handled\n if ((event as any)._smartSelectHandled) return;\n (event as any)._smartSelectHandled = true;\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n this.keyboardNavigating = true;\n clearTimeout(this.keyboardTimer);\n this.keyboardTimer = window.setTimeout(() => { this.keyboardNavigating = false; }, 100);\n\n if (!this.isOpen) {\n this.open();\n } else {\n // If searchable and search input is focused, move to first option\n const searchInput = this.shadowRoot.querySelector('.search-input') as HTMLInputElement;\n const isSearchFocused = this.searchable && searchInput === this.shadowRoot.activeElement;\n\n if (isSearchFocused) {\n this.focusedIndex = 0;\n searchInput.blur(); // Blur search input to allow normal navigation\n // Focus the component to ensure it receives keyboard events\n this.focus();\n this.updateFocusedOption();\n return;\n }\n // Navigate through options\n const newIndex = Math.min(this.focusedIndex + 1, this.filteredOptions.length - 1);\n this.focusedIndex = newIndex;\n this.updateFocusedOption();\n }\n break;\n\n case 'ArrowUp':\n event.preventDefault();\n this.keyboardNavigating = true;\n clearTimeout(this.keyboardTimer);\n this.keyboardTimer = window.setTimeout(() => { this.keyboardNavigating = false; }, 100);\n\n if (this.isOpen) {\n // If at first option and searchable, focus search input\n if (this.focusedIndex === 0 && this.searchable) {\n this.focusedIndex = -1;\n this.updateFocusedOption();\n requestAnimationFrame(() => {\n const searchInput = this.shadowRoot.querySelector('.search-input') as HTMLInputElement;\n if (searchInput) {\n searchInput.focus();\n searchInput.setSelectionRange(searchInput.value.length, searchInput.value.length);\n }\n });\n return;\n }\n // If searchable and search input is focused, do nothing\n const searchInput = this.shadowRoot.querySelector('.search-input') as HTMLInputElement;\n const isSearchFocused = this.searchable && searchInput === this.shadowRoot.activeElement;\n\n if (isSearchFocused) {\n return;\n }\n // Navigate through options\n const newIndex = Math.max(this.focusedIndex - 1, -1);\n this.focusedIndex = newIndex;\n this.updateFocusedOption();\n }\n break;\n\n case 'Enter':\n event.preventDefault();\n if (this.isOpen && this.focusedIndex >= 0 && this.focusedIndex < this.filteredOptions.length) {\n this.selectOption(this.filteredOptions[this.focusedIndex].value);\n } else if (!this.isOpen) {\n this.open();\n }\n break;\n\n case 'Escape':\n event.preventDefault();\n this.close();\n break;\n\n case 'Tab':\n this.close();\n break;\n }\n }\n\n /**\n * Binds all event listeners\n */\n private bindEvents(): void {\n // Listen for keydown events on both the component and shadow root\n const keydownHandler = this.handleKeydown.bind(this);\n this.addEventListener('keydown', keydownHandler);\n this.shadowRoot.addEventListener('keydown', keydownHandler as EventListener);\n\n // Use event delegation on the shadow root\n this.shadowRoot.addEventListener('click', (e) => {\n e.stopPropagation();\n const target = e.target as HTMLElement;\n\n if (target.closest('.remove-tag')) {\n const value = (target.closest('.remove-tag') as HTMLElement).dataset.value;\n if (value) this.deselectOption(value);\n } else if (target.closest('.option')) {\n const value = (target.closest('.option') as HTMLElement).dataset.value;\n if (value) this.selectOption(value);\n } else if (target.closest('.select-trigger')) {\n this.toggle();\n }\n });\n\n // Handle mouse hover on options to update focused index\n this.shadowRoot.addEventListener('mouseover', (e) => {\n // Don't interfere with keyboard navigation\n if (this.keyboardNavigating) return;\n\n const target = e.target as HTMLElement;\n if (target.closest('.option')) {\n const option = target.closest('.option') as HTMLElement;\n const options = Array.from(this.shadowRoot.querySelectorAll('.option'));\n const newFocusedIndex = options.indexOf(option);\n\n // Only update if the focused index actually changed\n if (this.focusedIndex !== newFocusedIndex) {\n // Remove focused class from current option\n const currentFocused = this.shadowRoot.querySelector('.option.focused');\n if (currentFocused) {\n currentFocused.classList.remove('focused');\n }\n\n // Add focused class to new option\n option.classList.add('focused');\n this.focusedIndex = newFocusedIndex;\n }\n }\n });\n\n // Handle mouse leaving dropdown to clear focus\n this.shadowRoot.addEventListener('mouseleave', (e) => {\n // Don't interfere with keyboard navigation\n if (this.keyboardNavigating) return;\n\n const target = e.target as HTMLElement;\n if (target.closest('.dropdown')) {\n const currentFocused = this.shadowRoot.querySelector('.option.focused');\n if (currentFocused) {\n currentFocused.classList.remove('focused');\n }\n this.focusedIndex = -1;\n }\n });\n\n // Handle search input\n this.shadowRoot.addEventListener('input', (e) => {\n const target = e.target as HTMLInputElement;\n if (target.classList.contains('search-input')) {\n this.handleSearch(target.value);\n }\n });\n\n // Close dropdown when clicking outside\n document.addEventListener('click', (e) => {\n if (!this.contains(e.target as Node)) {\n this.close();\n }\n });\n\n // Update dropdown position on window resize or scroll\n window.addEventListener('resize', () => {\n if (this.isOpen) {\n this._updateDropdownPosition();\n }\n });\n\n window.addEventListener('scroll', () => {\n if (this.isOpen) {\n this._updateDropdownPosition();\n }\n }, true); // Use capture to catch all scroll events\n }\n\n /**\n * Renders the component\n */\n private render(): void {\n // Initialize filteredOptions if not set\n if (this.filteredOptions.length === 0 && this.options.length > 0) {\n this.filteredOptions = [...this.options];\n }\n\n // Remember if search input was focused before render\n const wasSearchFocused = this.shadowRoot.querySelector('.search-input') === this.shadowRoot.activeElement;\n\n const displayText = this.selectedOptions.length > 0\n ? (this.multiple\n ? `${this.selectedOptions.length} selected`\n : this.selectedOptions[0].label)\n : this.placeholder;\n\n this.shadowRoot.innerHTML = `\n <style>\n :host {\n display: inline-block;\n position: relative;\n min-width: 200px;\n font-family: var(--font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);\n font-size: var(--font-size, 14px);\n outline: none;\n }\n\n :host(:focus) .select-trigger {\n border-color: var(--focus-color, #007bff);\n box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);\n }\n\n :host([disabled]) {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .select-container {\n position: relative;\n }\n\n .select-trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--padding, 8px 12px);\n border: var(--border, 1px solid #ccc);\n border-radius: var(--border-radius, 4px);\n background: var(--background, white);\n cursor: pointer;\n min-height: 36px;\n box-sizing: border-box;\n color: #333;\n user-select: none;\n }\n\n .select-trigger:focus {\n outline: none;\n border-color: var(--focus-color, #007bff);\n box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);\n }\n\n .select-trigger[disabled] {\n cursor: not-allowed;\n }\n\n .selected-content {\n display: flex;\n align-items: center;\n gap: 4px;\n flex-wrap: wrap;\n flex: 1;\n }\n\n .tag {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 8px;\n background: var(--tag-background, #e9ecef);\n border-radius: var(--tag-border-radius, 12px);\n font-size: 12px;\n color: var(--tag-color, #495057);\n user-select: none;\n }\n\n .remove-tag {\n cursor: pointer;\n color: var(--remove-color, #6c757d);\n font-weight: bold;\n font-size: 14px;\n }\n\n .remove-tag:hover {\n color: var(--remove-hover-color, #dc3545);\n }\n\n .arrow {\n width: 0;\n height: 0;\n border-left: 5px solid transparent;\n border-right: 5px solid transparent;\n border-top: 5px solid var(--arrow-color, #666);\n transition: transform 0.2s;\n }\n\n .arrow.open {\n transform: rotate(180deg);\n }\n\n .dropdown {\n position: fixed;\n z-index: 99999;\n background: var(--dropdown-background, white);\n border: var(--dropdown-border, 1px solid #ccc);\n border-radius: var(--dropdown-border-radius, 4px);\n box-shadow: var(--dropdown-shadow, 0 2px 8px rgba(0, 0, 0, 0.1));\n max-height: 200px;\n overflow-y: auto;\n scroll-behavior: smooth;\n color: #333;\n }\n\n .search-input {\n width: 100%;\n padding: 8px 12px;\n border: none;\n border-bottom: 1px solid #eee;\n font-size: 14px;\n outline: none;\n box-sizing: border-box;\n }\n\n .option {\n padding: 8px 12px;\n cursor: pointer;\n color: var(--option-color, #333);\n transition: background-color 0.2s;\n user-select: none;\n }\n\n .option:hover {\n background-color: var(--option-hover-background, #f8f9fa);\n }\n\n .option.focused {\n background-color: var(--option-focused-background, #007bff);\n color: var(--option-focused-color, white);\n }\n\n .option.selected {\n background-color: var(--option-selected-background, #e3f2fd);\n color: var(--option-selected-color, #1976d2);\n }\n\n .no-options {\n padding: 8px 12px;\n color: var(--no-options-color, #6c757d);\n font-style: italic;\n }\n </style>\n\n <div class=\"select-container\">\n <div class=\"select-trigger\" tabindex=\"-1\">\n <div class=\"selected-content\">\n ${this.multiple && this.selectedOptions.length > 0\n ? this.selectedOptions.map(option => `\n <span class=\"tag\">\n ${option.label}\n <span class=\"remove-tag\" data-value=\"${option.value}\">×</span>\n </span>\n `).join('')\n : `<span>${displayText}</span>`\n }\n </div>\n <div class=\"arrow ${this.isOpen ? 'open' : ''}\"></div>\n </div>\n\n ${this.isOpen ? `\n <div class=\"dropdown\">\n ${this.searchable ? `\n <input\n type=\"text\"\n class=\"search-input\"\n placeholder=\"Search options...\"\n value=\"${this.searchValue}\"\n >\n ` : ''}\n\n ${this.filteredOptions.length > 0\n ? this.filteredOptions.map((option, index) => `\n <div\n class=\"option ${this.selectedOptions.find(selected => selected.value === option.value) ? 'selected' : ''} ${index === this.focusedIndex ? 'focused' : ''}\"\n data-value=\"${option.value}\"\n >\n ${option.label}\n </div>\n `).join('')\n : '<div class=\"no-options\">No options available</div>'\n }\n </div>\n ` : ''}\n </div>\n `;\n\n // Re-focus search input if it was previously focused\n if (wasSearchFocused && this.searchable && this.isOpen) {\n requestAnimationFrame(() => {\n const searchInput = this.shadowRoot.querySelector('.search-input') as HTMLInputElement;\n if (searchInput) {\n searchInput.focus();\n // Restore cursor position to the end\n searchInput.setSelectionRange(searchInput.value.length, searchInput.value.length);\n }\n });\n }\n }\n}\n\n/**\n * Conditionally defines the custom element if in a browser environment.\n */\nconst defineSmartSelect = (tagName: string = 'liwe3-select'): void => {\n if (typeof window !== 'undefined' && !window.customElements.get(tagName)) {\n customElements.define(tagName, SmartSelectElement);\n }\n};\n\n// Auto-register with default tag name\ndefineSmartSelect();\n\nexport { defineSmartSelect };\n"],"names":["SmartSelectElement","name","oldValue","newValue","value","opt","val","option","optionsAttr","e","opts","searchInput","dropdown","options","query","focusedOption","dropdownRect","optionRect","trigger","triggerRect","viewportHeight","viewportWidth","dropdownMaxHeight","dropdownPadding","margin","spaceBelow","spaceAbove","shouldOpenUpward","width","left","top","maxHeight","position","event","newIndex","keydownHandler","target","newFocusedIndex","currentFocused","wasSearchFocused","displayText","index","selected","defineSmartSelect","tagName"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liwe3/webcomponents",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "A collection of reusable web components including SmartSelect and AITextEditor",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -57,4 +57,4 @@
|
|
|
57
57
|
"access": "public"
|
|
58
58
|
},
|
|
59
59
|
"packageManager": "pnpm@10.16.0"
|
|
60
|
-
}
|
|
60
|
+
}
|
package/src/SmartSelect.ts
CHANGED
|
@@ -597,6 +597,7 @@ export class SmartSelectElement extends HTMLElement {
|
|
|
597
597
|
min-height: 36px;
|
|
598
598
|
box-sizing: border-box;
|
|
599
599
|
color: #333;
|
|
600
|
+
user-select: none;
|
|
600
601
|
}
|
|
601
602
|
|
|
602
603
|
.select-trigger:focus {
|
|
@@ -626,6 +627,7 @@ export class SmartSelectElement extends HTMLElement {
|
|
|
626
627
|
border-radius: var(--tag-border-radius, 12px);
|
|
627
628
|
font-size: 12px;
|
|
628
629
|
color: var(--tag-color, #495057);
|
|
630
|
+
user-select: none;
|
|
629
631
|
}
|
|
630
632
|
|
|
631
633
|
.remove-tag {
|
|
@@ -680,6 +682,7 @@ export class SmartSelectElement extends HTMLElement {
|
|
|
680
682
|
cursor: pointer;
|
|
681
683
|
color: var(--option-color, #333);
|
|
682
684
|
transition: background-color 0.2s;
|
|
685
|
+
user-select: none;
|
|
683
686
|
}
|
|
684
687
|
|
|
685
688
|
.option:hover {
|