@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.
@@ -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 {
@@ -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.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
+ }
@@ -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 {