@wavelengthusaf/web-components 1.11.0 → 1.13.0

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.
@@ -3183,7 +3183,7 @@ if (!customElements.get("wavelength-progress-bar")) {
3183
3183
  }
3184
3184
 
3185
3185
  // src/web-components/wavelength-input.template.html
3186
- var wavelength_input_template_default = '<style>\n :host {\n display: block;\n width: 100%;\n font-family: sans-serif;\n --wavelength-container-background: #f8f8f8;\n --wavelength-label-background: #ffffff;\n }\n\n .field-wrapper {\n position: relative;\n }\n\n .floating-label {\n position: absolute;\n top: -0.325rem;\n left: 12px;\n font-size: 0.75rem;\n line-height: 1;\n color: var(--wavelength-label-color, #666666);\n padding: 0 4px;\n z-index: 1;\n pointer-events: none;\n user-select: none;\n }\n\n .floating-label::before,\n .floating-label::after {\n content: "";\n position: absolute;\n left: 0;\n width: 100%;\n z-index: -1;\n }\n\n .floating-label::before {\n top: 0;\n height: 50%;\n background: var(--wavelength-container-background, white);\n }\n\n .floating-label::after {\n bottom: 0;\n height: 50%;\n background: var(--wavelength-label-background, #ffffff);\n }\n\n :host([disabled]) .floating-label::before {\n opacity: 0;\n }\n\n input {\n font-size: 16px;\n padding: 16.5px 14px;\n border: 1px solid var(--wavelength-border-color, #cccccc);\n border-radius: 8px;\n width: 100%;\n box-sizing: border-box;\n background-color: var(--wavelength-background, #ffffff);\n transition: border-color 0.2s ease;\n overflow: auto;\n font-family: inherit;\n }\n\n input:focus {\n outline: none;\n }\n\n input:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n :host([disabled]) .floating-label::after {\n opacity: 0;\n cursor: not-allowed;\n }\n\n input::placeholder {\n color: #999999;\n }\n\n .helper-message {\n margin-top: 4px;\n font-size: 0.75rem;\n max-width: 100%;\n word-wrap: break-word;\n white-space: normal;\n overflow-wrap: break-word;\n color: #000000;\n padding-left: 14px;\n margin-left: 2px;\n user-select: none;\n }\n\n .required-marker {\n color: red;\n font-weight: lighter;\n font-size: 0.75rem;\n }\n\n .clear-button {\n position: absolute;\n right: 12px;\n top: 50%;\n transform: translateY(-50%);\n font-size: 1.25 rem;\n color: #666666;\n cursor: pointer;\n opacity: 0.5;\n user-select: none;\n transition: opacity 0.2s ease;\n z-index: 2;\n display: none;\n line-height: 1;\n padding: 0 4px;\n }\n\n .clear-button:hover {\n opacity: 1;\n }\n\n :host([disabled]) .clear-button {\n display: none;\n }\n</style>\n<div class="field-wrapper">\n <label class="floating-label" id="floating-label"></label>\n <div class="input-wrapper"></div>\n <div class="clear-button" id="clear-button" title="Clear input">\u2715</div>\n</div>\n<div class="helper-message" id="helper"></div>\n';
3186
+ var wavelength_input_template_default = '<style>\n :host {\n display: block;\n width: 100%;\n font-family: sans-serif;\n --wavelength-container-background: #f8f8f8;\n --wavelength-label-background: #ffffff;\n }\n\n .field-wrapper {\n position: relative;\n width: 100%;\n height: 100%;\n }\n\n .input-wrapper {\n width: 100%;\n height: 100%;\n }\n\n .floating-label {\n position: absolute;\n top: -0.325rem;\n left: 12px;\n font-size: 0.75rem;\n line-height: 1;\n color: var(--wavelength-label-color, #666666);\n padding: 0 4px;\n z-index: 1;\n pointer-events: none;\n user-select: none;\n }\n\n .floating-label::before,\n .floating-label::after {\n content: "";\n position: absolute;\n left: 0;\n width: 100%;\n z-index: -1;\n }\n\n .floating-label::before {\n top: 0;\n height: 50%;\n background: var(--wavelength-container-background, white);\n }\n\n .floating-label::after {\n bottom: 0;\n height: 50%;\n background: var(--wavelength-label-background, #ffffff);\n }\n\n :host([disabled]) .floating-label::before {\n opacity: 0;\n }\n\n input {\n font-size: 16px;\n padding: 16.5px 14px;\n border: 1px solid var(--wavelength-border-color, #cccccc);\n border-radius: 8px;\n width: 100%;\n box-sizing: border-box;\n background-color: var(--wavelength-background, #ffffff);\n transition: border-color 0.2s ease;\n overflow: auto;\n font-family: inherit;\n }\n\n input:focus {\n outline: none;\n }\n\n input:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n :host([disabled]) .floating-label::after {\n opacity: 0;\n cursor: not-allowed;\n }\n\n input::placeholder {\n color: #999999;\n }\n\n .helper-message {\n margin-top: 4px;\n font-size: 0.75rem;\n max-width: 100%;\n word-wrap: break-word;\n white-space: normal;\n overflow-wrap: break-word;\n color: #000000;\n padding-left: 14px;\n margin-left: 2px;\n user-select: none;\n }\n\n .required-marker {\n color: red;\n font-weight: lighter;\n font-size: 0.75rem;\n }\n\n .clear-button {\n position: absolute;\n right: 12px;\n top: 50%;\n transform: translateY(-50%);\n font-size: 1.25 rem;\n color: #666666;\n cursor: pointer;\n opacity: 0.5;\n user-select: none;\n transition: opacity 0.2s ease;\n z-index: 2;\n display: none;\n line-height: 1;\n padding: 0 4px;\n }\n\n .clear-button:hover {\n opacity: 1;\n }\n\n :host([disabled]) .clear-button {\n display: none;\n }\n</style>\n<div class="field-wrapper">\n <label class="floating-label" id="floating-label"></label>\n <div class="input-wrapper"></div>\n <div class="clear-button" id="clear-button" title="Clear input">\u2715</div>\n</div>\n<div class="helper-message" id="helper"></div>\n';
3187
3187
 
3188
3188
  // src/web-components/wavelength-input.ts
3189
3189
  function getAncestor(el) {
@@ -3302,7 +3302,9 @@ var BaseWavelengthInput = class extends HTMLElement {
3302
3302
  "max-length",
3303
3303
  "required",
3304
3304
  "force-error",
3305
- "label"
3305
+ "label",
3306
+ "font-size",
3307
+ "font-family"
3306
3308
  ];
3307
3309
  }
3308
3310
  connectedCallback() {
@@ -3430,6 +3432,7 @@ var BaseWavelengthInput = class extends HTMLElement {
3430
3432
  }
3431
3433
  this.helperEl.innerHTML = htmlMessage;
3432
3434
  this.helperEl.classList.add("error");
3435
+ this.helperEl.style.display = "block";
3433
3436
  this.inputEl.style.borderColor = "red";
3434
3437
  this.helperEl.style.color = "red";
3435
3438
  this.inputEl.setAttribute("aria-invalid", "true");
@@ -3442,6 +3445,7 @@ var BaseWavelengthInput = class extends HTMLElement {
3442
3445
  this.helperEl.textContent = helperText;
3443
3446
  this.helperEl.classList.remove("error");
3444
3447
  this.helperEl.style.color = helperColor;
3448
+ this.helperEl.style.display = helperText ? "block" : "none";
3445
3449
  this.inputEl.style.borderColor = borderColor;
3446
3450
  this.inputEl.setAttribute("aria-invalid", "false");
3447
3451
  this.removeAttribute("data-error");
@@ -3519,6 +3523,12 @@ var BaseWavelengthInput = class extends HTMLElement {
3519
3523
  this.inputEl.style.padding = rawPadding;
3520
3524
  this.inputEl.style.height = this.getAttribute("height") || "";
3521
3525
  this.inputEl.style.borderRadius = this.getAttribute("border-radius") || "8px";
3526
+ if (this.hasAttribute("font-size")) {
3527
+ this.inputEl.style.fontSize = this.getAttribute("font-size");
3528
+ }
3529
+ if (this.hasAttribute("font-family")) {
3530
+ this.inputEl.style.fontFamily = this.getAttribute("font-family");
3531
+ }
3522
3532
  this.helperEl.style.width = helperWidth;
3523
3533
  this.helperEl.style.paddingLeft = `${leftPaddingPx}px`;
3524
3534
  }
@@ -3564,6 +3574,7 @@ var BaseWavelengthInput = class extends HTMLElement {
3564
3574
  if (!hasError) {
3565
3575
  this.helperEl.textContent = helper;
3566
3576
  this.helperEl.style.color = helperColor;
3577
+ this.helperEl.style.display = helper ? "block" : "none";
3567
3578
  }
3568
3579
  }
3569
3580
  _applyAccessibility() {
@@ -3588,7 +3599,10 @@ var BaseWavelengthInput = class extends HTMLElement {
3588
3599
  this.inputEl.name = newValue || "";
3589
3600
  break;
3590
3601
  case "label":
3602
+ case "font-size":
3603
+ case "font-family":
3591
3604
  this._applyContent();
3605
+ this._applyLayout();
3592
3606
  break;
3593
3607
  case "helper-message":
3594
3608
  this._applyValidationHint();
@@ -6506,6 +6520,270 @@ if (!customElements.get("wavelength-pagination")) {
6506
6520
  customElements.define("wavelength-pagination", WavelengthPagination);
6507
6521
  }
6508
6522
 
6523
+ // src/web-components/wavelength-search.template.html
6524
+ var wavelength_search_template_default = '<style>\n :host {\n display: block;\n --width: 200px;\n --height: 32px;\n --border-width: 1px;\n --mode: automatic;\n --font-size: 14px;\n --border-radius: 50px;\n --border-color: #000;\n --background-color: #fff;\n --hover-color: #007bff;\n --placeholder-color: #999;\n --placeholder-font: "Montserrat", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;\n --input-color: #000;\n --input-font: "Montserrat", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;\n }\n\n :host([height="small"]) {\n --height: 32px;\n }\n\n :host([height="medium"]) {\n --height: 48px;\n }\n\n :host([height="large"]) {\n --height: 64px;\n }\n\n .flex-container {\n display: block;\n flex-direction: column;\n width: fit-content;\n height: fit-content;\n position: relative;\n }\n\n .searchbar-wrapper {\n display: flex;\n flex-direction: row;\n align-items: center;\n border-radius: var(--border-radius);\n border: var(--border-width) solid var(--border-color);\n background-color: var(--background-color);\n width: var(--width);\n height: var(--height);\n margin: 1px;\n }\n\n .searchbar-wrapper:hover {\n border-color: var(--hover-color);\n }\n\n .searchbar-wrapper:focus-within {\n border-width: calc(var(--border-width) + 1px);\n border-color: var(--hover-color);\n margin: 0px;\n }\n\n :host([icon-pos="end"]) .searchbar-wrapper {\n flex-direction: row-reverse;\n }\n\n .search-button {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background-color: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 10px;\n padding: 0;\n transition: background-color 0.2s;\n }\n\n .search-button:hover {\n background-color: rgba(0, 0, 0, 0.05);\n }\n\n .search-icon {\n width: var(--font-size);\n height: var(--font-size);\n fill: currentColor;\n }\n\n .input-container {\n position: relative;\n flex-grow: 1;\n display: flex;\n align-items: center;\n height: 100%;\n }\n\n .animated-placeholder {\n position: absolute;\n left: 14px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--placeholder-color);\n font-family: var(--placeholder-font);\n font-size: var(--font-size);\n pointer-events: none;\n transition: all 0.2s ease;\n background-color: transparent;\n padding: 0 4px;\n border-radius: 4px;\n z-index: 5;\n }\n\n .input-container.focused .animated-placeholder,\n .input-container.has-value .animated-placeholder {\n top: -12px;\n font-size: calc(var(--font-size) * 0.75);\n color: var(--placeholder-color);\n background-color: transparent;\n }\n\n .dropdown {\n position: absolute;\n font-size: var(--font-size);\n font-family: var(--input-font);\n top: calc(100% + 4px);\n left: 0;\n max-height: 200px;\n width: 100%;\n background: white;\n border: 1px solid transparent;\n border-radius: 4px;\n display: none;\n z-index: 10;\n overflow-y: auto;\n overflow-x: hidden;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n }\n\n .dropdown-item {\n padding: 8px 14px;\n cursor: pointer;\n border-left: 3px solid transparent;\n transition:\n background-color 0.1s,\n border-color 0.1s;\n }\n .dropdown-item:hover {\n background-color: rgba(0, 0, 0, 0.05);\n }\n .dropdown-item.highlighted {\n background-color: rgba(0, 0, 0, 0.08);\n border-left-color: var(--hover-color);\n }\n\n wavelength-input {\n flex-grow: 1;\n width: 100%;\n height: 100%;\n }\n</style>\n\n<div class="flex-container">\n <div class="searchbar-wrapper">\n <button class="search-button search-icon">\n <svg\n version="1.1"\n id="_x32_"\n xmlns="http://www.w3.org/2000/svg"\n xmlns:xlink="http://www.w3.org/1999/xlink"\n viewBox="0 0 512 512"\n xml:space="preserve"\n fill="#000000"\n style="width: 100%; height: 100%"\n >\n <g id="SVGRepo_bgCarrier" stroke-width="0"></g>\n <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>\n <g id="SVGRepo_iconCarrier">\n <style type="text/css">\n .st0 {\n fill: #000000;\n }\n </style>\n <g>\n <path\n class="st0"\n d="M312.069,53.445c-71.26-71.26-187.194-71.26-258.454,0c-71.261,71.26-71.261,187.206,0,258.466 c71.26,71.26,187.194,71.26,258.454,0S383.329,124.705,312.069,53.445z M286.694,286.536 c-57.351,57.34-150.353,57.34-207.704-0.011s-57.351-150.353,0-207.693c57.351-57.351,150.342-57.351,207.693,0 S344.045,229.174,286.694,286.536z"\n ></path>\n <path\n class="st0"\n d="M101.911,112.531c-29.357,37.725-31.801,89.631-7.321,129.702c1.877,3.087,5.902,4.048,8.978,2.182 c3.065-1.888,4.037-5.903,2.16-8.978c-21.666-35.456-19.506-81.538,6.469-114.876c2.226-2.837,1.713-6.938-1.135-9.154 C108.227,109.193,104.125,109.695,101.911,112.531z"\n ></path>\n <path\n class="st0"\n d="M498.544,447.722l-132.637-129.2c-7.255-7.07-18.84-6.982-26.008,0.174l-21.033,21.033 c-7.156,7.156-7.234,18.742-0.153,25.986l129.19,132.636c14.346,17.324,35.542,18.35,51.917,1.964 C516.216,483.951,515.857,462.068,498.544,447.722z"\n ></path>\n </g>\n </g>\n </svg>\n </button>\n <div class="input-container" id="inputContainer">\n <label class="animated-placeholder" id="animatedPlaceholder">Search...</label>\n <wavelength-input\n focus-color="transparent"\n background-color="transparent"\n border-color="transparent"\n label=""\n id="searchInput"\n placeholder=""\n validation-type="onBlur"\n min-length="0"\n clearable\n height="100%"\n padding="0 10px"\n ></wavelength-input>\n <div id="dropdown" class="dropdown"></div>\n </div>\n </div>\n</div>\n';
6525
+
6526
+ // src/web-components/wavelength-search.ts
6527
+ var WavelengthSearch = class extends HTMLElement {
6528
+ constructor() {
6529
+ super();
6530
+ this.options = [];
6531
+ this.highlightedIndex = -1;
6532
+ this.styleAttributes = [
6533
+ "width",
6534
+ "height",
6535
+ "font-size",
6536
+ "border-width",
6537
+ "border-radius",
6538
+ "border-color",
6539
+ "background-color",
6540
+ "hover-color",
6541
+ "placeholder-color",
6542
+ "placeholder-font",
6543
+ "input-color",
6544
+ "input-font"
6545
+ ];
6546
+ this.handleFocusIn = () => {
6547
+ this.inputContainer.classList.add("focused");
6548
+ };
6549
+ this.handleFocusOut = () => {
6550
+ this.inputContainer.classList.remove("focused");
6551
+ };
6552
+ this.handleInputChange = (e) => {
6553
+ const mode = this.getAttribute("mode") || "automatic";
6554
+ const value = e.detail.value;
6555
+ if (value) {
6556
+ this.inputContainer.classList.add("has-value");
6557
+ } else {
6558
+ this.inputContainer.classList.remove("has-value");
6559
+ }
6560
+ if (mode === "automatic") {
6561
+ if (this.searchTimeout) {
6562
+ clearTimeout(this.searchTimeout);
6563
+ }
6564
+ this.searchTimeout = setTimeout(() => {
6565
+ this.handleSearch(value);
6566
+ }, 300);
6567
+ }
6568
+ };
6569
+ this.handleKeydown = (e) => {
6570
+ const isDropdownVisible = this.dropdown.style.display === "block";
6571
+ const items = this.dropdown.querySelectorAll(".dropdown-item");
6572
+ if (e.key === "ArrowDown") {
6573
+ e.preventDefault();
6574
+ if (!isDropdownVisible) {
6575
+ this.handleSearch(this.input.value);
6576
+ } else if (items.length > 0) {
6577
+ this.highlightedIndex = (this.highlightedIndex + 1) % items.length;
6578
+ this.updateHighlight(items);
6579
+ }
6580
+ } else if (e.key === "ArrowUp") {
6581
+ e.preventDefault();
6582
+ if (isDropdownVisible && items.length > 0) {
6583
+ this.highlightedIndex = this.highlightedIndex <= 0 ? items.length - 1 : this.highlightedIndex - 1;
6584
+ this.updateHighlight(items);
6585
+ }
6586
+ } else if (e.key === "Escape" || e.key === "Tab") {
6587
+ this.dropdown.style.display = "none";
6588
+ this.highlightedIndex = -1;
6589
+ if (e.key === "Escape") {
6590
+ this.input.focus();
6591
+ }
6592
+ } else if (e.key === "Enter") {
6593
+ if (isDropdownVisible && this.highlightedIndex >= 0 && this.highlightedIndex < items.length) {
6594
+ e.preventDefault();
6595
+ this.selectOption(items[this.highlightedIndex].textContent || "");
6596
+ } else {
6597
+ const value = this.input.value;
6598
+ this.dispatchEvent(new CustomEvent("wavelength-search-submit", { detail: { value }, bubbles: true, composed: true }));
6599
+ this.handleSearch(value);
6600
+ }
6601
+ }
6602
+ };
6603
+ this.handleSearchIconClick = () => {
6604
+ const value = this.input.value;
6605
+ this.dispatchEvent(new CustomEvent("wavelength-search-submit", { detail: { value }, bubbles: true, composed: true }));
6606
+ this.handleSearch(value);
6607
+ };
6608
+ this.handleDocumentClick = (e) => {
6609
+ if (!this.contains(e.target)) {
6610
+ this.dropdown.style.display = "none";
6611
+ this.highlightedIndex = -1;
6612
+ }
6613
+ };
6614
+ this.shadow = this.attachShadow({ mode: "open" });
6615
+ this.shadow.innerHTML = wavelength_search_template_default;
6616
+ }
6617
+ static get observedAttributes() {
6618
+ return [
6619
+ "width",
6620
+ "height",
6621
+ "mode",
6622
+ "font-size",
6623
+ "border-width",
6624
+ "border-radius",
6625
+ "border-color",
6626
+ "background-color",
6627
+ "hover-color",
6628
+ "options",
6629
+ "placeholder",
6630
+ "icon-pos",
6631
+ "placeholder-color",
6632
+ "placeholder-font",
6633
+ "input-color",
6634
+ "input-font"
6635
+ ];
6636
+ }
6637
+ connectedCallback() {
6638
+ this._syncStyles();
6639
+ this.input = this.shadow.getElementById("searchInput");
6640
+ this.dropdown = this.shadow.getElementById("dropdown");
6641
+ this.inputContainer = this.shadow.getElementById("inputContainer");
6642
+ this.animatedPlaceholder = this.shadow.getElementById("animatedPlaceholder");
6643
+ if (!this.hasAttribute("icon-pos")) {
6644
+ this.setAttribute("icon-pos", "end");
6645
+ }
6646
+ if (!this.hasAttribute("height")) {
6647
+ this.setAttribute("height", "small");
6648
+ }
6649
+ const placeholder = this.getAttribute("placeholder") || "Search...";
6650
+ this.animatedPlaceholder.textContent = placeholder;
6651
+ const searchIcon = this.shadow.querySelector(".search-icon");
6652
+ this.input.addEventListener("focusin", this.handleFocusIn);
6653
+ this.input.addEventListener("focusout", this.handleFocusOut);
6654
+ this.input.addEventListener("inputChange", this.handleInputChange);
6655
+ this.input.addEventListener("keydown", this.handleKeydown);
6656
+ if (searchIcon) {
6657
+ searchIcon.addEventListener("click", this.handleSearchIconClick);
6658
+ }
6659
+ document.addEventListener("click", this.handleDocumentClick);
6660
+ }
6661
+ disconnectedCallback() {
6662
+ this.input.removeEventListener("focusin", this.handleFocusIn);
6663
+ this.input.removeEventListener("focusout", this.handleFocusOut);
6664
+ this.input.removeEventListener("inputChange", this.handleInputChange);
6665
+ this.input.removeEventListener("keydown", this.handleKeydown);
6666
+ const searchIcon = this.shadow.querySelector(".search-icon");
6667
+ if (searchIcon) {
6668
+ searchIcon.removeEventListener("click", this.handleSearchIconClick);
6669
+ }
6670
+ document.removeEventListener("click", this.handleDocumentClick);
6671
+ }
6672
+ attributeChangedCallback(name, oldValue, newValue) {
6673
+ if (oldValue === newValue) return;
6674
+ if (this.styleAttributes.includes(name)) {
6675
+ if (name === "height") {
6676
+ if (["small", "medium", "large"].includes(newValue || "")) {
6677
+ this.style.removeProperty("--height");
6678
+ } else if (newValue !== null) {
6679
+ this.style.setProperty("--height", newValue);
6680
+ } else {
6681
+ this.style.removeProperty("--height");
6682
+ }
6683
+ } else {
6684
+ if (newValue !== null) {
6685
+ this.style.setProperty(`--${name}`, newValue);
6686
+ } else {
6687
+ this.style.removeProperty(`--${name}`);
6688
+ }
6689
+ }
6690
+ }
6691
+ if (name === "options" && newValue) {
6692
+ try {
6693
+ this.options = JSON.parse(newValue);
6694
+ } catch (e) {
6695
+ this.options = newValue.split(",").map((s) => s.trim());
6696
+ }
6697
+ } else if (name === "placeholder" && this.animatedPlaceholder) {
6698
+ this.animatedPlaceholder.textContent = newValue || "Search...";
6699
+ } else if (name === "font-size" && this.input) {
6700
+ this.input.setAttribute("font-size", newValue || "");
6701
+ } else if (name === "input-color" && this.input) {
6702
+ this.input.setAttribute("text-color", newValue || "");
6703
+ } else if (name === "input-font" && this.input) {
6704
+ this.input.setAttribute("font-family", newValue || "");
6705
+ }
6706
+ }
6707
+ handleSearch(query) {
6708
+ if (this.searchTimeout) {
6709
+ clearTimeout(this.searchTimeout);
6710
+ this.searchTimeout = null;
6711
+ }
6712
+ if (!query) {
6713
+ this.dropdown.style.display = "none";
6714
+ return;
6715
+ }
6716
+ const results = this.options.filter((option) => option.toLowerCase().includes(query.toLowerCase()));
6717
+ this.highlightedIndex = -1;
6718
+ this.renderDropdown(results);
6719
+ }
6720
+ renderDropdown(results) {
6721
+ if (results.length === 0) {
6722
+ this.dropdown.style.display = "none";
6723
+ return;
6724
+ }
6725
+ this.dropdown.innerHTML = results.map((r) => `<div class="dropdown-item">${r}</div>`).join("");
6726
+ this.dropdown.style.display = "block";
6727
+ const items = this.dropdown.querySelectorAll(".dropdown-item");
6728
+ items.forEach((item, index) => {
6729
+ item.addEventListener("click", () => {
6730
+ this.selectOption(item.textContent || "");
6731
+ });
6732
+ item.addEventListener("mouseenter", () => {
6733
+ this.highlightedIndex = index;
6734
+ this.updateHighlight(items);
6735
+ });
6736
+ });
6737
+ this.updateHighlight(items);
6738
+ }
6739
+ selectOption(value) {
6740
+ this.input.value = value;
6741
+ this.dropdown.style.display = "none";
6742
+ this.highlightedIndex = -1;
6743
+ this.dispatchEvent(new CustomEvent("wavelength-search-select", { detail: { value }, bubbles: true, composed: true }));
6744
+ }
6745
+ // ---- Getters and Setters API ---- //
6746
+ get value() {
6747
+ return this.input.value;
6748
+ }
6749
+ set value(val) {
6750
+ this.input.value = val;
6751
+ }
6752
+ get optionsList() {
6753
+ return this.options;
6754
+ }
6755
+ set optionsList(val) {
6756
+ if (val) {
6757
+ this.options = val;
6758
+ this.setAttribute("options", JSON.stringify(val));
6759
+ }
6760
+ }
6761
+ _syncStyles() {
6762
+ this.styleAttributes.forEach((attr) => {
6763
+ const value = this.getAttribute(attr);
6764
+ if (value) {
6765
+ if (attr === "height" && ["small", "medium", "large"].includes(value)) {
6766
+ } else {
6767
+ this.style.setProperty(`--${attr}`, value);
6768
+ }
6769
+ }
6770
+ });
6771
+ }
6772
+ updateHighlight(items) {
6773
+ items.forEach((item, index) => {
6774
+ const isHighlighted = index === this.highlightedIndex;
6775
+ item.classList.toggle("highlighted", isHighlighted);
6776
+ if (isHighlighted) {
6777
+ item.scrollIntoView({ block: "nearest" });
6778
+ }
6779
+ });
6780
+ }
6781
+ };
6782
+ if (!customElements.get("wavelength-search")) {
6783
+ customElements.define("wavelength-search", WavelengthSearch);
6784
+ }
6785
+
6786
+
6509
6787
 
6510
6788
 
6511
6789
 
@@ -6529,7 +6807,7 @@ if (!customElements.get("wavelength-pagination")) {
6529
6807
 
6530
6808
 
6531
6809
 
6532
- exports.BaseWavelengthInput = BaseWavelengthInput; exports.BaseWavelengthMultiSelectAutocomplete = BaseWavelengthMultiSelectAutocomplete; exports.ChildDataTable = ChildDataTable; exports.SampleComponent = SampleComponent; exports.WavelengthBanner = WavelengthBanner; exports.WavelengthButton = WavelengthButton; exports.WavelengthCheckbox = WavelengthCheckbox; exports.WavelengthDatePicker = WavelengthDatePicker; exports.WavelengthDropdown = WavelengthDropdown; exports.WavelengthFileDropZone = WavelengthFileDropZone; exports.WavelengthForm = WavelengthForm; exports.WavelengthInput = WavelengthInput; exports.WavelengthManyPlanes = WavelengthManyPlanes; exports.WavelengthMenu = WavelengthMenu; exports.WavelengthMultiSelectAutocomplete = WavelengthMultiSelectAutocomplete; exports.WavelengthNavBar = WavelengthNavBar; exports.WavelengthNotificationPanel = WavelengthNotificationPanel; exports.WavelengthPagination = WavelengthPagination; exports.WavelengthPlaneTrail = WavelengthPlaneTrail; exports.WavelengthProgressBar = WavelengthProgressBar; exports.WavelengthSnackbar = WavelengthSnackbar; exports.WavelengthTitleBar = WavelengthTitleBar; exports.WavelengthToolTip = WavelengthToolTip;
6810
+ exports.BaseWavelengthInput = BaseWavelengthInput; exports.BaseWavelengthMultiSelectAutocomplete = BaseWavelengthMultiSelectAutocomplete; exports.ChildDataTable = ChildDataTable; exports.SampleComponent = SampleComponent; exports.WavelengthBanner = WavelengthBanner; exports.WavelengthButton = WavelengthButton; exports.WavelengthCheckbox = WavelengthCheckbox; exports.WavelengthDatePicker = WavelengthDatePicker; exports.WavelengthDropdown = WavelengthDropdown; exports.WavelengthFileDropZone = WavelengthFileDropZone; exports.WavelengthForm = WavelengthForm; exports.WavelengthInput = WavelengthInput; exports.WavelengthManyPlanes = WavelengthManyPlanes; exports.WavelengthMenu = WavelengthMenu; exports.WavelengthMultiSelectAutocomplete = WavelengthMultiSelectAutocomplete; exports.WavelengthNavBar = WavelengthNavBar; exports.WavelengthNotificationPanel = WavelengthNotificationPanel; exports.WavelengthPagination = WavelengthPagination; exports.WavelengthPlaneTrail = WavelengthPlaneTrail; exports.WavelengthProgressBar = WavelengthProgressBar; exports.WavelengthSearch = WavelengthSearch; exports.WavelengthSnackbar = WavelengthSnackbar; exports.WavelengthTitleBar = WavelengthTitleBar; exports.WavelengthToolTip = WavelengthToolTip;
6533
6811
  /*! Bundled license information:
6534
6812
 
6535
6813
  react/cjs/react.production.min.js:
@@ -2308,4 +2308,36 @@ declare class WavelengthPagination extends HTMLElement {
2308
2308
  private _syncStyles;
2309
2309
  }
2310
2310
 
2311
- export { BaseWavelengthInput, BaseWavelengthMultiSelectAutocomplete, type CheckboxElements, ChildDataTable, SampleComponent, WavelengthBanner, WavelengthButton, WavelengthCheckbox, WavelengthDatePicker, WavelengthDropdown, WavelengthFileDropZone, WavelengthForm, WavelengthInput, WavelengthManyPlanes, WavelengthMenu, WavelengthMultiSelectAutocomplete, WavelengthNavBar, WavelengthNotificationPanel, WavelengthPagination, WavelengthPlaneTrail, WavelengthProgressBar, WavelengthSnackbar, WavelengthTitleBar, WavelengthToolTip };
2311
+ declare class WavelengthSearch extends HTMLElement {
2312
+ static get observedAttributes(): string[];
2313
+ private shadow;
2314
+ private input;
2315
+ private dropdown;
2316
+ private inputContainer;
2317
+ private animatedPlaceholder;
2318
+ private options;
2319
+ private highlightedIndex;
2320
+ private styleAttributes;
2321
+ constructor();
2322
+ connectedCallback(): void;
2323
+ disconnectedCallback(): void;
2324
+ attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
2325
+ private handleSearch;
2326
+ private renderDropdown;
2327
+ private selectOption;
2328
+ get value(): string;
2329
+ set value(val: string);
2330
+ get optionsList(): string[] | undefined;
2331
+ set optionsList(val: string[] | undefined);
2332
+ private _syncStyles;
2333
+ private handleFocusIn;
2334
+ private handleFocusOut;
2335
+ private searchTimeout;
2336
+ private handleInputChange;
2337
+ private handleKeydown;
2338
+ private updateHighlight;
2339
+ private handleSearchIconClick;
2340
+ private handleDocumentClick;
2341
+ }
2342
+
2343
+ export { BaseWavelengthInput, BaseWavelengthMultiSelectAutocomplete, type CheckboxElements, ChildDataTable, SampleComponent, WavelengthBanner, WavelengthButton, WavelengthCheckbox, WavelengthDatePicker, WavelengthDropdown, WavelengthFileDropZone, WavelengthForm, WavelengthInput, WavelengthManyPlanes, WavelengthMenu, WavelengthMultiSelectAutocomplete, WavelengthNavBar, WavelengthNotificationPanel, WavelengthPagination, WavelengthPlaneTrail, WavelengthProgressBar, WavelengthSearch, WavelengthSnackbar, WavelengthTitleBar, WavelengthToolTip };
@@ -2308,4 +2308,36 @@ declare class WavelengthPagination extends HTMLElement {
2308
2308
  private _syncStyles;
2309
2309
  }
2310
2310
 
2311
- export { BaseWavelengthInput, BaseWavelengthMultiSelectAutocomplete, type CheckboxElements, ChildDataTable, SampleComponent, WavelengthBanner, WavelengthButton, WavelengthCheckbox, WavelengthDatePicker, WavelengthDropdown, WavelengthFileDropZone, WavelengthForm, WavelengthInput, WavelengthManyPlanes, WavelengthMenu, WavelengthMultiSelectAutocomplete, WavelengthNavBar, WavelengthNotificationPanel, WavelengthPagination, WavelengthPlaneTrail, WavelengthProgressBar, WavelengthSnackbar, WavelengthTitleBar, WavelengthToolTip };
2311
+ declare class WavelengthSearch extends HTMLElement {
2312
+ static get observedAttributes(): string[];
2313
+ private shadow;
2314
+ private input;
2315
+ private dropdown;
2316
+ private inputContainer;
2317
+ private animatedPlaceholder;
2318
+ private options;
2319
+ private highlightedIndex;
2320
+ private styleAttributes;
2321
+ constructor();
2322
+ connectedCallback(): void;
2323
+ disconnectedCallback(): void;
2324
+ attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
2325
+ private handleSearch;
2326
+ private renderDropdown;
2327
+ private selectOption;
2328
+ get value(): string;
2329
+ set value(val: string);
2330
+ get optionsList(): string[] | undefined;
2331
+ set optionsList(val: string[] | undefined);
2332
+ private _syncStyles;
2333
+ private handleFocusIn;
2334
+ private handleFocusOut;
2335
+ private searchTimeout;
2336
+ private handleInputChange;
2337
+ private handleKeydown;
2338
+ private updateHighlight;
2339
+ private handleSearchIconClick;
2340
+ private handleDocumentClick;
2341
+ }
2342
+
2343
+ export { BaseWavelengthInput, BaseWavelengthMultiSelectAutocomplete, type CheckboxElements, ChildDataTable, SampleComponent, WavelengthBanner, WavelengthButton, WavelengthCheckbox, WavelengthDatePicker, WavelengthDropdown, WavelengthFileDropZone, WavelengthForm, WavelengthInput, WavelengthManyPlanes, WavelengthMenu, WavelengthMultiSelectAutocomplete, WavelengthNavBar, WavelengthNotificationPanel, WavelengthPagination, WavelengthPlaneTrail, WavelengthProgressBar, WavelengthSearch, WavelengthSnackbar, WavelengthTitleBar, WavelengthToolTip };
package/dist/esm/index.js CHANGED
@@ -3183,7 +3183,7 @@ if (!customElements.get("wavelength-progress-bar")) {
3183
3183
  }
3184
3184
 
3185
3185
  // src/web-components/wavelength-input.template.html
3186
- var wavelength_input_template_default = '<style>\n :host {\n display: block;\n width: 100%;\n font-family: sans-serif;\n --wavelength-container-background: #f8f8f8;\n --wavelength-label-background: #ffffff;\n }\n\n .field-wrapper {\n position: relative;\n }\n\n .floating-label {\n position: absolute;\n top: -0.325rem;\n left: 12px;\n font-size: 0.75rem;\n line-height: 1;\n color: var(--wavelength-label-color, #666666);\n padding: 0 4px;\n z-index: 1;\n pointer-events: none;\n user-select: none;\n }\n\n .floating-label::before,\n .floating-label::after {\n content: "";\n position: absolute;\n left: 0;\n width: 100%;\n z-index: -1;\n }\n\n .floating-label::before {\n top: 0;\n height: 50%;\n background: var(--wavelength-container-background, white);\n }\n\n .floating-label::after {\n bottom: 0;\n height: 50%;\n background: var(--wavelength-label-background, #ffffff);\n }\n\n :host([disabled]) .floating-label::before {\n opacity: 0;\n }\n\n input {\n font-size: 16px;\n padding: 16.5px 14px;\n border: 1px solid var(--wavelength-border-color, #cccccc);\n border-radius: 8px;\n width: 100%;\n box-sizing: border-box;\n background-color: var(--wavelength-background, #ffffff);\n transition: border-color 0.2s ease;\n overflow: auto;\n font-family: inherit;\n }\n\n input:focus {\n outline: none;\n }\n\n input:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n :host([disabled]) .floating-label::after {\n opacity: 0;\n cursor: not-allowed;\n }\n\n input::placeholder {\n color: #999999;\n }\n\n .helper-message {\n margin-top: 4px;\n font-size: 0.75rem;\n max-width: 100%;\n word-wrap: break-word;\n white-space: normal;\n overflow-wrap: break-word;\n color: #000000;\n padding-left: 14px;\n margin-left: 2px;\n user-select: none;\n }\n\n .required-marker {\n color: red;\n font-weight: lighter;\n font-size: 0.75rem;\n }\n\n .clear-button {\n position: absolute;\n right: 12px;\n top: 50%;\n transform: translateY(-50%);\n font-size: 1.25 rem;\n color: #666666;\n cursor: pointer;\n opacity: 0.5;\n user-select: none;\n transition: opacity 0.2s ease;\n z-index: 2;\n display: none;\n line-height: 1;\n padding: 0 4px;\n }\n\n .clear-button:hover {\n opacity: 1;\n }\n\n :host([disabled]) .clear-button {\n display: none;\n }\n</style>\n<div class="field-wrapper">\n <label class="floating-label" id="floating-label"></label>\n <div class="input-wrapper"></div>\n <div class="clear-button" id="clear-button" title="Clear input">\u2715</div>\n</div>\n<div class="helper-message" id="helper"></div>\n';
3186
+ var wavelength_input_template_default = '<style>\n :host {\n display: block;\n width: 100%;\n font-family: sans-serif;\n --wavelength-container-background: #f8f8f8;\n --wavelength-label-background: #ffffff;\n }\n\n .field-wrapper {\n position: relative;\n width: 100%;\n height: 100%;\n }\n\n .input-wrapper {\n width: 100%;\n height: 100%;\n }\n\n .floating-label {\n position: absolute;\n top: -0.325rem;\n left: 12px;\n font-size: 0.75rem;\n line-height: 1;\n color: var(--wavelength-label-color, #666666);\n padding: 0 4px;\n z-index: 1;\n pointer-events: none;\n user-select: none;\n }\n\n .floating-label::before,\n .floating-label::after {\n content: "";\n position: absolute;\n left: 0;\n width: 100%;\n z-index: -1;\n }\n\n .floating-label::before {\n top: 0;\n height: 50%;\n background: var(--wavelength-container-background, white);\n }\n\n .floating-label::after {\n bottom: 0;\n height: 50%;\n background: var(--wavelength-label-background, #ffffff);\n }\n\n :host([disabled]) .floating-label::before {\n opacity: 0;\n }\n\n input {\n font-size: 16px;\n padding: 16.5px 14px;\n border: 1px solid var(--wavelength-border-color, #cccccc);\n border-radius: 8px;\n width: 100%;\n box-sizing: border-box;\n background-color: var(--wavelength-background, #ffffff);\n transition: border-color 0.2s ease;\n overflow: auto;\n font-family: inherit;\n }\n\n input:focus {\n outline: none;\n }\n\n input:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n :host([disabled]) .floating-label::after {\n opacity: 0;\n cursor: not-allowed;\n }\n\n input::placeholder {\n color: #999999;\n }\n\n .helper-message {\n margin-top: 4px;\n font-size: 0.75rem;\n max-width: 100%;\n word-wrap: break-word;\n white-space: normal;\n overflow-wrap: break-word;\n color: #000000;\n padding-left: 14px;\n margin-left: 2px;\n user-select: none;\n }\n\n .required-marker {\n color: red;\n font-weight: lighter;\n font-size: 0.75rem;\n }\n\n .clear-button {\n position: absolute;\n right: 12px;\n top: 50%;\n transform: translateY(-50%);\n font-size: 1.25 rem;\n color: #666666;\n cursor: pointer;\n opacity: 0.5;\n user-select: none;\n transition: opacity 0.2s ease;\n z-index: 2;\n display: none;\n line-height: 1;\n padding: 0 4px;\n }\n\n .clear-button:hover {\n opacity: 1;\n }\n\n :host([disabled]) .clear-button {\n display: none;\n }\n</style>\n<div class="field-wrapper">\n <label class="floating-label" id="floating-label"></label>\n <div class="input-wrapper"></div>\n <div class="clear-button" id="clear-button" title="Clear input">\u2715</div>\n</div>\n<div class="helper-message" id="helper"></div>\n';
3187
3187
 
3188
3188
  // src/web-components/wavelength-input.ts
3189
3189
  function getAncestor(el) {
@@ -3302,7 +3302,9 @@ var BaseWavelengthInput = class extends HTMLElement {
3302
3302
  "max-length",
3303
3303
  "required",
3304
3304
  "force-error",
3305
- "label"
3305
+ "label",
3306
+ "font-size",
3307
+ "font-family"
3306
3308
  ];
3307
3309
  }
3308
3310
  connectedCallback() {
@@ -3430,6 +3432,7 @@ var BaseWavelengthInput = class extends HTMLElement {
3430
3432
  }
3431
3433
  this.helperEl.innerHTML = htmlMessage;
3432
3434
  this.helperEl.classList.add("error");
3435
+ this.helperEl.style.display = "block";
3433
3436
  this.inputEl.style.borderColor = "red";
3434
3437
  this.helperEl.style.color = "red";
3435
3438
  this.inputEl.setAttribute("aria-invalid", "true");
@@ -3442,6 +3445,7 @@ var BaseWavelengthInput = class extends HTMLElement {
3442
3445
  this.helperEl.textContent = helperText;
3443
3446
  this.helperEl.classList.remove("error");
3444
3447
  this.helperEl.style.color = helperColor;
3448
+ this.helperEl.style.display = helperText ? "block" : "none";
3445
3449
  this.inputEl.style.borderColor = borderColor;
3446
3450
  this.inputEl.setAttribute("aria-invalid", "false");
3447
3451
  this.removeAttribute("data-error");
@@ -3519,6 +3523,12 @@ var BaseWavelengthInput = class extends HTMLElement {
3519
3523
  this.inputEl.style.padding = rawPadding;
3520
3524
  this.inputEl.style.height = this.getAttribute("height") || "";
3521
3525
  this.inputEl.style.borderRadius = this.getAttribute("border-radius") || "8px";
3526
+ if (this.hasAttribute("font-size")) {
3527
+ this.inputEl.style.fontSize = this.getAttribute("font-size");
3528
+ }
3529
+ if (this.hasAttribute("font-family")) {
3530
+ this.inputEl.style.fontFamily = this.getAttribute("font-family");
3531
+ }
3522
3532
  this.helperEl.style.width = helperWidth;
3523
3533
  this.helperEl.style.paddingLeft = `${leftPaddingPx}px`;
3524
3534
  }
@@ -3564,6 +3574,7 @@ var BaseWavelengthInput = class extends HTMLElement {
3564
3574
  if (!hasError) {
3565
3575
  this.helperEl.textContent = helper;
3566
3576
  this.helperEl.style.color = helperColor;
3577
+ this.helperEl.style.display = helper ? "block" : "none";
3567
3578
  }
3568
3579
  }
3569
3580
  _applyAccessibility() {
@@ -3588,7 +3599,10 @@ var BaseWavelengthInput = class extends HTMLElement {
3588
3599
  this.inputEl.name = newValue || "";
3589
3600
  break;
3590
3601
  case "label":
3602
+ case "font-size":
3603
+ case "font-family":
3591
3604
  this._applyContent();
3605
+ this._applyLayout();
3592
3606
  break;
3593
3607
  case "helper-message":
3594
3608
  this._applyValidationHint();
@@ -6505,6 +6519,269 @@ var WavelengthPagination = class extends HTMLElement {
6505
6519
  if (!customElements.get("wavelength-pagination")) {
6506
6520
  customElements.define("wavelength-pagination", WavelengthPagination);
6507
6521
  }
6522
+
6523
+ // src/web-components/wavelength-search.template.html
6524
+ var wavelength_search_template_default = '<style>\n :host {\n display: block;\n --width: 200px;\n --height: 32px;\n --border-width: 1px;\n --mode: automatic;\n --font-size: 14px;\n --border-radius: 50px;\n --border-color: #000;\n --background-color: #fff;\n --hover-color: #007bff;\n --placeholder-color: #999;\n --placeholder-font: "Montserrat", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;\n --input-color: #000;\n --input-font: "Montserrat", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;\n }\n\n :host([height="small"]) {\n --height: 32px;\n }\n\n :host([height="medium"]) {\n --height: 48px;\n }\n\n :host([height="large"]) {\n --height: 64px;\n }\n\n .flex-container {\n display: block;\n flex-direction: column;\n width: fit-content;\n height: fit-content;\n position: relative;\n }\n\n .searchbar-wrapper {\n display: flex;\n flex-direction: row;\n align-items: center;\n border-radius: var(--border-radius);\n border: var(--border-width) solid var(--border-color);\n background-color: var(--background-color);\n width: var(--width);\n height: var(--height);\n margin: 1px;\n }\n\n .searchbar-wrapper:hover {\n border-color: var(--hover-color);\n }\n\n .searchbar-wrapper:focus-within {\n border-width: calc(var(--border-width) + 1px);\n border-color: var(--hover-color);\n margin: 0px;\n }\n\n :host([icon-pos="end"]) .searchbar-wrapper {\n flex-direction: row-reverse;\n }\n\n .search-button {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background-color: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 10px;\n padding: 0;\n transition: background-color 0.2s;\n }\n\n .search-button:hover {\n background-color: rgba(0, 0, 0, 0.05);\n }\n\n .search-icon {\n width: var(--font-size);\n height: var(--font-size);\n fill: currentColor;\n }\n\n .input-container {\n position: relative;\n flex-grow: 1;\n display: flex;\n align-items: center;\n height: 100%;\n }\n\n .animated-placeholder {\n position: absolute;\n left: 14px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--placeholder-color);\n font-family: var(--placeholder-font);\n font-size: var(--font-size);\n pointer-events: none;\n transition: all 0.2s ease;\n background-color: transparent;\n padding: 0 4px;\n border-radius: 4px;\n z-index: 5;\n }\n\n .input-container.focused .animated-placeholder,\n .input-container.has-value .animated-placeholder {\n top: -12px;\n font-size: calc(var(--font-size) * 0.75);\n color: var(--placeholder-color);\n background-color: transparent;\n }\n\n .dropdown {\n position: absolute;\n font-size: var(--font-size);\n font-family: var(--input-font);\n top: calc(100% + 4px);\n left: 0;\n max-height: 200px;\n width: 100%;\n background: white;\n border: 1px solid transparent;\n border-radius: 4px;\n display: none;\n z-index: 10;\n overflow-y: auto;\n overflow-x: hidden;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n }\n\n .dropdown-item {\n padding: 8px 14px;\n cursor: pointer;\n border-left: 3px solid transparent;\n transition:\n background-color 0.1s,\n border-color 0.1s;\n }\n .dropdown-item:hover {\n background-color: rgba(0, 0, 0, 0.05);\n }\n .dropdown-item.highlighted {\n background-color: rgba(0, 0, 0, 0.08);\n border-left-color: var(--hover-color);\n }\n\n wavelength-input {\n flex-grow: 1;\n width: 100%;\n height: 100%;\n }\n</style>\n\n<div class="flex-container">\n <div class="searchbar-wrapper">\n <button class="search-button search-icon">\n <svg\n version="1.1"\n id="_x32_"\n xmlns="http://www.w3.org/2000/svg"\n xmlns:xlink="http://www.w3.org/1999/xlink"\n viewBox="0 0 512 512"\n xml:space="preserve"\n fill="#000000"\n style="width: 100%; height: 100%"\n >\n <g id="SVGRepo_bgCarrier" stroke-width="0"></g>\n <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>\n <g id="SVGRepo_iconCarrier">\n <style type="text/css">\n .st0 {\n fill: #000000;\n }\n </style>\n <g>\n <path\n class="st0"\n d="M312.069,53.445c-71.26-71.26-187.194-71.26-258.454,0c-71.261,71.26-71.261,187.206,0,258.466 c71.26,71.26,187.194,71.26,258.454,0S383.329,124.705,312.069,53.445z M286.694,286.536 c-57.351,57.34-150.353,57.34-207.704-0.011s-57.351-150.353,0-207.693c57.351-57.351,150.342-57.351,207.693,0 S344.045,229.174,286.694,286.536z"\n ></path>\n <path\n class="st0"\n d="M101.911,112.531c-29.357,37.725-31.801,89.631-7.321,129.702c1.877,3.087,5.902,4.048,8.978,2.182 c3.065-1.888,4.037-5.903,2.16-8.978c-21.666-35.456-19.506-81.538,6.469-114.876c2.226-2.837,1.713-6.938-1.135-9.154 C108.227,109.193,104.125,109.695,101.911,112.531z"\n ></path>\n <path\n class="st0"\n d="M498.544,447.722l-132.637-129.2c-7.255-7.07-18.84-6.982-26.008,0.174l-21.033,21.033 c-7.156,7.156-7.234,18.742-0.153,25.986l129.19,132.636c14.346,17.324,35.542,18.35,51.917,1.964 C516.216,483.951,515.857,462.068,498.544,447.722z"\n ></path>\n </g>\n </g>\n </svg>\n </button>\n <div class="input-container" id="inputContainer">\n <label class="animated-placeholder" id="animatedPlaceholder">Search...</label>\n <wavelength-input\n focus-color="transparent"\n background-color="transparent"\n border-color="transparent"\n label=""\n id="searchInput"\n placeholder=""\n validation-type="onBlur"\n min-length="0"\n clearable\n height="100%"\n padding="0 10px"\n ></wavelength-input>\n <div id="dropdown" class="dropdown"></div>\n </div>\n </div>\n</div>\n';
6525
+
6526
+ // src/web-components/wavelength-search.ts
6527
+ var WavelengthSearch = class extends HTMLElement {
6528
+ constructor() {
6529
+ super();
6530
+ this.options = [];
6531
+ this.highlightedIndex = -1;
6532
+ this.styleAttributes = [
6533
+ "width",
6534
+ "height",
6535
+ "font-size",
6536
+ "border-width",
6537
+ "border-radius",
6538
+ "border-color",
6539
+ "background-color",
6540
+ "hover-color",
6541
+ "placeholder-color",
6542
+ "placeholder-font",
6543
+ "input-color",
6544
+ "input-font"
6545
+ ];
6546
+ this.handleFocusIn = () => {
6547
+ this.inputContainer.classList.add("focused");
6548
+ };
6549
+ this.handleFocusOut = () => {
6550
+ this.inputContainer.classList.remove("focused");
6551
+ };
6552
+ this.handleInputChange = (e) => {
6553
+ const mode = this.getAttribute("mode") || "automatic";
6554
+ const value = e.detail.value;
6555
+ if (value) {
6556
+ this.inputContainer.classList.add("has-value");
6557
+ } else {
6558
+ this.inputContainer.classList.remove("has-value");
6559
+ }
6560
+ if (mode === "automatic") {
6561
+ if (this.searchTimeout) {
6562
+ clearTimeout(this.searchTimeout);
6563
+ }
6564
+ this.searchTimeout = setTimeout(() => {
6565
+ this.handleSearch(value);
6566
+ }, 300);
6567
+ }
6568
+ };
6569
+ this.handleKeydown = (e) => {
6570
+ const isDropdownVisible = this.dropdown.style.display === "block";
6571
+ const items = this.dropdown.querySelectorAll(".dropdown-item");
6572
+ if (e.key === "ArrowDown") {
6573
+ e.preventDefault();
6574
+ if (!isDropdownVisible) {
6575
+ this.handleSearch(this.input.value);
6576
+ } else if (items.length > 0) {
6577
+ this.highlightedIndex = (this.highlightedIndex + 1) % items.length;
6578
+ this.updateHighlight(items);
6579
+ }
6580
+ } else if (e.key === "ArrowUp") {
6581
+ e.preventDefault();
6582
+ if (isDropdownVisible && items.length > 0) {
6583
+ this.highlightedIndex = this.highlightedIndex <= 0 ? items.length - 1 : this.highlightedIndex - 1;
6584
+ this.updateHighlight(items);
6585
+ }
6586
+ } else if (e.key === "Escape" || e.key === "Tab") {
6587
+ this.dropdown.style.display = "none";
6588
+ this.highlightedIndex = -1;
6589
+ if (e.key === "Escape") {
6590
+ this.input.focus();
6591
+ }
6592
+ } else if (e.key === "Enter") {
6593
+ if (isDropdownVisible && this.highlightedIndex >= 0 && this.highlightedIndex < items.length) {
6594
+ e.preventDefault();
6595
+ this.selectOption(items[this.highlightedIndex].textContent || "");
6596
+ } else {
6597
+ const value = this.input.value;
6598
+ this.dispatchEvent(new CustomEvent("wavelength-search-submit", { detail: { value }, bubbles: true, composed: true }));
6599
+ this.handleSearch(value);
6600
+ }
6601
+ }
6602
+ };
6603
+ this.handleSearchIconClick = () => {
6604
+ const value = this.input.value;
6605
+ this.dispatchEvent(new CustomEvent("wavelength-search-submit", { detail: { value }, bubbles: true, composed: true }));
6606
+ this.handleSearch(value);
6607
+ };
6608
+ this.handleDocumentClick = (e) => {
6609
+ if (!this.contains(e.target)) {
6610
+ this.dropdown.style.display = "none";
6611
+ this.highlightedIndex = -1;
6612
+ }
6613
+ };
6614
+ this.shadow = this.attachShadow({ mode: "open" });
6615
+ this.shadow.innerHTML = wavelength_search_template_default;
6616
+ }
6617
+ static get observedAttributes() {
6618
+ return [
6619
+ "width",
6620
+ "height",
6621
+ "mode",
6622
+ "font-size",
6623
+ "border-width",
6624
+ "border-radius",
6625
+ "border-color",
6626
+ "background-color",
6627
+ "hover-color",
6628
+ "options",
6629
+ "placeholder",
6630
+ "icon-pos",
6631
+ "placeholder-color",
6632
+ "placeholder-font",
6633
+ "input-color",
6634
+ "input-font"
6635
+ ];
6636
+ }
6637
+ connectedCallback() {
6638
+ this._syncStyles();
6639
+ this.input = this.shadow.getElementById("searchInput");
6640
+ this.dropdown = this.shadow.getElementById("dropdown");
6641
+ this.inputContainer = this.shadow.getElementById("inputContainer");
6642
+ this.animatedPlaceholder = this.shadow.getElementById("animatedPlaceholder");
6643
+ if (!this.hasAttribute("icon-pos")) {
6644
+ this.setAttribute("icon-pos", "end");
6645
+ }
6646
+ if (!this.hasAttribute("height")) {
6647
+ this.setAttribute("height", "small");
6648
+ }
6649
+ const placeholder = this.getAttribute("placeholder") || "Search...";
6650
+ this.animatedPlaceholder.textContent = placeholder;
6651
+ const searchIcon = this.shadow.querySelector(".search-icon");
6652
+ this.input.addEventListener("focusin", this.handleFocusIn);
6653
+ this.input.addEventListener("focusout", this.handleFocusOut);
6654
+ this.input.addEventListener("inputChange", this.handleInputChange);
6655
+ this.input.addEventListener("keydown", this.handleKeydown);
6656
+ if (searchIcon) {
6657
+ searchIcon.addEventListener("click", this.handleSearchIconClick);
6658
+ }
6659
+ document.addEventListener("click", this.handleDocumentClick);
6660
+ }
6661
+ disconnectedCallback() {
6662
+ this.input.removeEventListener("focusin", this.handleFocusIn);
6663
+ this.input.removeEventListener("focusout", this.handleFocusOut);
6664
+ this.input.removeEventListener("inputChange", this.handleInputChange);
6665
+ this.input.removeEventListener("keydown", this.handleKeydown);
6666
+ const searchIcon = this.shadow.querySelector(".search-icon");
6667
+ if (searchIcon) {
6668
+ searchIcon.removeEventListener("click", this.handleSearchIconClick);
6669
+ }
6670
+ document.removeEventListener("click", this.handleDocumentClick);
6671
+ }
6672
+ attributeChangedCallback(name, oldValue, newValue) {
6673
+ if (oldValue === newValue) return;
6674
+ if (this.styleAttributes.includes(name)) {
6675
+ if (name === "height") {
6676
+ if (["small", "medium", "large"].includes(newValue || "")) {
6677
+ this.style.removeProperty("--height");
6678
+ } else if (newValue !== null) {
6679
+ this.style.setProperty("--height", newValue);
6680
+ } else {
6681
+ this.style.removeProperty("--height");
6682
+ }
6683
+ } else {
6684
+ if (newValue !== null) {
6685
+ this.style.setProperty(`--${name}`, newValue);
6686
+ } else {
6687
+ this.style.removeProperty(`--${name}`);
6688
+ }
6689
+ }
6690
+ }
6691
+ if (name === "options" && newValue) {
6692
+ try {
6693
+ this.options = JSON.parse(newValue);
6694
+ } catch (e) {
6695
+ this.options = newValue.split(",").map((s) => s.trim());
6696
+ }
6697
+ } else if (name === "placeholder" && this.animatedPlaceholder) {
6698
+ this.animatedPlaceholder.textContent = newValue || "Search...";
6699
+ } else if (name === "font-size" && this.input) {
6700
+ this.input.setAttribute("font-size", newValue || "");
6701
+ } else if (name === "input-color" && this.input) {
6702
+ this.input.setAttribute("text-color", newValue || "");
6703
+ } else if (name === "input-font" && this.input) {
6704
+ this.input.setAttribute("font-family", newValue || "");
6705
+ }
6706
+ }
6707
+ handleSearch(query) {
6708
+ if (this.searchTimeout) {
6709
+ clearTimeout(this.searchTimeout);
6710
+ this.searchTimeout = null;
6711
+ }
6712
+ if (!query) {
6713
+ this.dropdown.style.display = "none";
6714
+ return;
6715
+ }
6716
+ const results = this.options.filter((option) => option.toLowerCase().includes(query.toLowerCase()));
6717
+ this.highlightedIndex = -1;
6718
+ this.renderDropdown(results);
6719
+ }
6720
+ renderDropdown(results) {
6721
+ if (results.length === 0) {
6722
+ this.dropdown.style.display = "none";
6723
+ return;
6724
+ }
6725
+ this.dropdown.innerHTML = results.map((r) => `<div class="dropdown-item">${r}</div>`).join("");
6726
+ this.dropdown.style.display = "block";
6727
+ const items = this.dropdown.querySelectorAll(".dropdown-item");
6728
+ items.forEach((item, index) => {
6729
+ item.addEventListener("click", () => {
6730
+ this.selectOption(item.textContent || "");
6731
+ });
6732
+ item.addEventListener("mouseenter", () => {
6733
+ this.highlightedIndex = index;
6734
+ this.updateHighlight(items);
6735
+ });
6736
+ });
6737
+ this.updateHighlight(items);
6738
+ }
6739
+ selectOption(value) {
6740
+ this.input.value = value;
6741
+ this.dropdown.style.display = "none";
6742
+ this.highlightedIndex = -1;
6743
+ this.dispatchEvent(new CustomEvent("wavelength-search-select", { detail: { value }, bubbles: true, composed: true }));
6744
+ }
6745
+ // ---- Getters and Setters API ---- //
6746
+ get value() {
6747
+ return this.input.value;
6748
+ }
6749
+ set value(val) {
6750
+ this.input.value = val;
6751
+ }
6752
+ get optionsList() {
6753
+ return this.options;
6754
+ }
6755
+ set optionsList(val) {
6756
+ if (val) {
6757
+ this.options = val;
6758
+ this.setAttribute("options", JSON.stringify(val));
6759
+ }
6760
+ }
6761
+ _syncStyles() {
6762
+ this.styleAttributes.forEach((attr) => {
6763
+ const value = this.getAttribute(attr);
6764
+ if (value) {
6765
+ if (attr === "height" && ["small", "medium", "large"].includes(value)) {
6766
+ } else {
6767
+ this.style.setProperty(`--${attr}`, value);
6768
+ }
6769
+ }
6770
+ });
6771
+ }
6772
+ updateHighlight(items) {
6773
+ items.forEach((item, index) => {
6774
+ const isHighlighted = index === this.highlightedIndex;
6775
+ item.classList.toggle("highlighted", isHighlighted);
6776
+ if (isHighlighted) {
6777
+ item.scrollIntoView({ block: "nearest" });
6778
+ }
6779
+ });
6780
+ }
6781
+ };
6782
+ if (!customElements.get("wavelength-search")) {
6783
+ customElements.define("wavelength-search", WavelengthSearch);
6784
+ }
6508
6785
  export {
6509
6786
  BaseWavelengthInput,
6510
6787
  BaseWavelengthMultiSelectAutocomplete,
@@ -6526,6 +6803,7 @@ export {
6526
6803
  WavelengthPagination,
6527
6804
  WavelengthPlaneTrail,
6528
6805
  WavelengthProgressBar,
6806
+ WavelengthSearch,
6529
6807
  WavelengthSnackbar,
6530
6808
  WavelengthTitleBar,
6531
6809
  WavelengthToolTip
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@wavelengthusaf/web-components",
3
3
  "author": "563 EWS - Wavelength",
4
4
  "license": "MIT",
5
- "version": "1.11.0",
5
+ "version": "1.13.0",
6
6
  "description": "Common component library used by Wavelength developers (NATIVE WEB COMPONENTS)",
7
7
  "main": "/dist/cjs/index.cjs",
8
8
  "module": "/dist/esm/index.js",