jb-select 7.2.1 → 7.3.1

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.
@@ -1,5 +1,6 @@
1
1
  import type { JBSelectWebComponent } from '../jb-select';
2
2
  import CSS from './jb-option.css';
3
+ import CSSVariable from './variables.css';
3
4
  import { renderHTML } from "./render";
4
5
  import type { JBOptionElements } from "./types";
5
6
  import { removeCheckboxNodes } from './utils';
@@ -104,7 +105,7 @@ export class JBOptionWebComponent<TValue> extends HTMLElement {
104
105
  mode: "open",
105
106
  serializable: true
106
107
  });
107
- const html = `<style>${CSS}</style>\n${renderHTML()}`;
108
+ const html = `<style>${CSSVariable} \n ${CSS}</style>\n${renderHTML()}`;
108
109
  const element = document.createElement("template");
109
110
  element.innerHTML = html;
110
111
  shadowRoot.appendChild(element.content.cloneNode(true));
@@ -139,6 +140,7 @@ export class JBOptionWebComponent<TValue> extends HTMLElement {
139
140
  this.#value = value as TValue;
140
141
  }
141
142
  }
143
+
142
144
  #onOptionClick() {
143
145
  if (this.#isChangeCalled) {
144
146
  this.#isChangeCalled = false;
@@ -158,6 +160,13 @@ export class JBOptionWebComponent<TValue> extends HTMLElement {
158
160
  }
159
161
  }
160
162
  }
163
+ /**
164
+ * @public
165
+ * this function used by jb-select to toggle option when it active and user hit enter to select or deselect option
166
+ */
167
+ toggleOption(){
168
+ this.#onOptionClick();
169
+ }
161
170
  #dispatchSelectEvent() {
162
171
  const event = new Event("select", { bubbles: true, cancelable: false, composed: true });
163
172
  this.dispatchEvent(event);
@@ -183,6 +192,18 @@ export class JBOptionWebComponent<TValue> extends HTMLElement {
183
192
  }
184
193
  }
185
194
  }
195
+ #active = false;
196
+ get active(){
197
+ return this.#active;
198
+ }
199
+ set active(value:boolean){
200
+ this.#active = value;
201
+ if(value){
202
+ this.#internals?.states.add("active");
203
+ }else{
204
+ this.#internals?.states.delete("active");
205
+ }
206
+ }
186
207
 
187
208
  }
188
209
  const myElementNotExists = !customElements.get("jb-option");
@@ -1,5 +1,12 @@
1
1
  :host{
2
- --background-color:var(--jb-select-option-background-color, transparent);
3
- --background-color-hover:var(--jb-select-option-background-color-hover, #1073db);
4
- --option-color-hover:var(--jb-select-option-color-hover, #fff);
2
+ /*Sizes*/
3
+ --border-radius:var(--jb-option-border-radius, 0);
4
+ --padding: var(--jb-option-padding, 0.5rem 1rem);
5
+ --font-size: var(--jb-option-font-size, 0.9rem);
6
+ --min-height: var(--jb-option-min-height, 2.25rem);
7
+ /*Colors*/
8
+ --color: var(--jb-option-color, inherit);
9
+ --color-active: var(--jb-option-color-active, var(--jb-option-color, inherit));
10
+ --background-color:var(--jb-option-background-color, transparent);
11
+ --background-color-active:var(--jb-option-background-color-active, var(--jb-primary-subtle));
5
12
  }
@@ -23,6 +23,9 @@ export class JBOptionListWebComponent<TOption, TValue> extends HTMLElement {
23
23
  this.#optionList = value;
24
24
  this.#initOptionList(value);
25
25
  }
26
+ get optionListDom(){
27
+ return Array.from(this.#optionPairMap.values());
28
+ }
26
29
  constructor() {
27
30
  super();
28
31
  this.#initWebComponent();
package/lib/jb-select.css CHANGED
@@ -213,6 +213,7 @@
213
213
 
214
214
  .popover-wrapper {
215
215
  position: relative;
216
+ --jb-popover-padding: 0;
216
217
 
217
218
  .select-list-wrapper {
218
219
  @media(--tablet-from) {
package/lib/jb-select.ts CHANGED
@@ -19,6 +19,7 @@ import { dictionary } from "./i18n";
19
19
  import { i18n } from "jb-core/i18n";
20
20
  import type { JBButtonWebComponent } from "jb-button";
21
21
  import { JBPopoverWebComponent } from "jb-popover";
22
+ import { JBOptionListWebComponent } from "./jb-option-list/jb-option-list";
22
23
 
23
24
  //TODO: add IncludeInputInList or freeSolo so user can select item that he wrote without even it exist in select list
24
25
  //TODO: handleHomeEndKeys to move focus inside the popup with the Home and End keys.
@@ -57,6 +58,21 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
57
58
  if (value === undefined) return;
58
59
  this.#popoverPosition = value;
59
60
  }
61
+ /**
62
+ * this is a expensive option list please use it when you really need optionList with order
63
+ */
64
+ get optionListWithOrder(): JBOptionWebComponent<TValue>[] {
65
+ const elements = this.elements.optionListSlot.assignedElements();
66
+ const optionList = elements.flatMap(x => {
67
+ // extract option list from JBOptionList to make option list flat by index
68
+ if (x instanceof JBOptionListWebComponent) {
69
+ return x.optionListDom;
70
+ } else {
71
+ return x
72
+ }
73
+ }).filter(x => (x instanceof JBOptionWebComponent && !x.hidden));
74
+ return optionList as JBOptionWebComponent<TValue>[];
75
+ }
60
76
  get multiple() {
61
77
  return this.hasAttribute('multiple')
62
78
  }
@@ -379,15 +395,15 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
379
395
  } else if (this.value) {
380
396
  this.#setValueFromOutside(this.value);
381
397
  }
382
- if (this.multiple && Array.isArray(this.#value) && this.#selectedOptions.values.length< this.#value.length) {
398
+ if (this.multiple && Array.isArray(this.#value) && this.#selectedOptions.values.length < this.#value.length) {
383
399
  //in this particular edge case our value is already set but some option maybe missing in first place and added later
384
- const missing:JBOptionWebComponent<TValue>[] = [];
385
- this.#optionList.forEach((op)=>{
386
- if(op.selected == false && (this.#value as unknown[]).includes(op.value)){
400
+ const missing: JBOptionWebComponent<TValue>[] = [];
401
+ this.#optionList.forEach((op) => {
402
+ if (op.selected == false && (this.#value as unknown[]).includes(op.value)) {
387
403
  missing.push(op);
388
404
  }
389
405
  });
390
- if(missing.length>0){
406
+ if (missing.length > 0) {
391
407
  this.#setSelectedOption(missing);
392
408
  }
393
409
  }
@@ -463,7 +479,7 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
463
479
  this.#notFoundedValue = null;
464
480
  this.#value = value;
465
481
  if (value === null || value === undefined || (Array.isArray(value) && value.length === 0)) {
466
- this.textValue = "";
482
+ if(!this.multiple){this.textValue = "";}
467
483
  this.#updateSelectedOptionDom();
468
484
  //will deselect all option
469
485
  this.#setSelectedOption(null);
@@ -473,7 +489,9 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
473
489
  this.elements.input.placeholder = this.placeholder;
474
490
  }
475
491
  } else {
476
- this.textValue = "";
492
+
493
+ if(!this.multiple){this.textValue = "";}
494
+ //for typescript error
477
495
  Array.isArray(option) ? this.#setSelectedOption(option) : this.#setSelectedOption(option);
478
496
  this.#updateSelectedOptionDom();
479
497
  this.elements.componentWrapper.classList.add("--has-value");
@@ -483,7 +501,9 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
483
501
  }
484
502
  }
485
503
  //if user select an option we rest filter so user see all option again when open a select
486
- this.#updateOptionList("");
504
+ if(!this.multiple){
505
+ this.#updateOptionList("");
506
+ }
487
507
  }
488
508
  #onArrowKeyClick() {
489
509
  if (this.isOpen) {
@@ -503,6 +523,8 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
503
523
  const event = createKeyboardEvent("keypress", e, {})
504
524
  this.dispatchEvent(event);
505
525
  }
526
+
527
+
506
528
  #onInputBeforeInput(_e: InputEvent) {
507
529
  // const inputtedText = e.data || "";
508
530
  //TODO: add cancelable event dispatch here
@@ -526,9 +548,60 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
526
548
  //because on keypress dont receive backspace key press
527
549
  this.#handleSelectedValueDisplay(inputText);
528
550
  }
529
-
551
+ switch (e.key) {
552
+ case "ArrowUp":
553
+ this.#activePrevOption();
554
+ break;
555
+ case "ArrowDown":
556
+ this.#activeNextOption();
557
+ break;
558
+ case "Enter":
559
+ this.#optionList.forEach(x => {
560
+ if (x.active) {x.toggleOption();}
561
+ })
562
+ break;
563
+ }
530
564
  this.#triggerOnInputKeyup(e);
531
565
  }
566
+ /**
567
+ * used when change activeItem with arrow keys
568
+ */
569
+ #activePrevOption() {
570
+ const optionList = this.optionListWithOrder;
571
+ const activeOption = optionList.find((option, index) => {
572
+ if (option.active) {
573
+ if (optionList[index - 1]) {
574
+ option.active = false;
575
+ optionList[index - 1].active = true;
576
+ optionList[index - 1].scrollIntoView({ block: "nearest" });
577
+ }
578
+ return true;
579
+ }
580
+ return false
581
+ });
582
+ if (!activeOption && optionList[optionList.length - 1]) {
583
+ optionList[optionList.length - 1].active = true;
584
+ optionList[optionList.length - 1].scrollIntoView({ block: "nearest" });
585
+ }
586
+ }
587
+ /**
588
+ * used when change activeItem with arrow keys
589
+ */
590
+ #activeNextOption() {
591
+ const optionList = this.optionListWithOrder;
592
+ const activeOption = optionList.find((option, index) => {
593
+ if (option.active) {
594
+ if (optionList[index + 1]) {
595
+ option.active = false;
596
+ optionList[index + 1].active = true;
597
+ optionList[index + 1].scrollIntoView({ block: "nearest" });
598
+ }
599
+ return true;
600
+ }
601
+ return false
602
+ });
603
+ if (!activeOption && optionList[0]) { optionList[0].active = true; optionList[0].scrollIntoView({ block: "nearest" }) }
604
+ }
532
605
  #handleSelectedValueDisplay(inputValue: string) {
533
606
  if (inputValue !== "") {
534
607
  this.elements.selectedValueWrapper.classList.add("--search-typed");
@@ -599,6 +672,7 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
599
672
  }
600
673
  }
601
674
  this.elements.input.blur();
675
+ this.#optionList.forEach(x => { x.active = false })
602
676
  }
603
677
  #showOptionList() {
604
678
  this.#internals.states.add("open")
@@ -637,13 +711,13 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
637
711
  target.selected = false;
638
712
  this.#selectedOptions.delete(e.target as JBOptionWebComponent<TValue>)
639
713
  this.#updateSelectedOptionDom();
640
- if(Array.isArray(this.#value)){
714
+ if (Array.isArray(this.#value)) {
641
715
  const index = this.#value.indexOf(target.value);
642
- if(index !== -1) this.#value.splice(index,1);
643
- }else if(this.value === target.value){
716
+ if (index !== -1) this.#value.splice(index, 1);
717
+ } else if (this.value === target.value) {
644
718
  this.#value = null;
645
719
  }
646
- this.#value=this.#value
720
+ this.#value = this.#value
647
721
  this.#checkValidity(true);
648
722
  }
649
723
  //called when an jb-Option connected to the dom
@@ -657,6 +731,7 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
657
731
  this.#setValueOnOptionListChanged();
658
732
  }
659
733
  this.#updateListEmptyPlaceholder();
734
+ target.addEventListener("mouseenter",this.#onOptionHover)
660
735
  }
661
736
  #onOptionDisconnected(e: CustomEvent) {
662
737
  e.stopPropagation();
@@ -666,14 +741,21 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
666
741
  if (target.value == this.#value) {
667
742
  this.#setValueOnOptionListChanged();
668
743
  }
744
+ target.removeEventListener("mouseenter",this.#onOptionHover)
745
+ }
746
+ #onOptionHover = (e:MouseEvent)=>{
747
+ const target = e.target as JBOptionWebComponent<TValue>;
748
+ if(!target.active){
749
+ this.#optionList.forEach(x=>{x.active = false});
750
+ }
751
+ target.active = true;
669
752
  }
670
-
671
753
  #selectOption(value: TValue, optionDom: JBOptionWebComponent<TValue>) {
672
- if(this.multiple){
673
- if(Array.isArray(this.#value)){
674
- value = [...this.#value,value] as TValue
675
- }else{
676
- value = [this.#value,value] as TValue
754
+ if (this.multiple) {
755
+ if (Array.isArray(this.#value)) {
756
+ value = [...this.#value, value] as TValue
757
+ } else {
758
+ value = [this.#value, value] as TValue
677
759
  }
678
760
  }
679
761
  this.#setValue(value, optionDom);
package/package.json CHANGED
@@ -16,7 +16,7 @@
16
16
  "web component",
17
17
  "react component"
18
18
  ],
19
- "version": "7.2.1",
19
+ "version": "7.3.1",
20
20
  "bugs": "https://github.com/javadbat/jb-select/issues",
21
21
  "homepage": "https://javadbat.github.io/design-system/?path=/story/components-form-elements-jbselect",
22
22
  "license": "MIT",
@@ -37,7 +37,7 @@
37
37
  "dependencies": {
38
38
  "jb-validation": ">=0.4.0",
39
39
  "jb-button": ">=3.9.1",
40
- "jb-popover": ">=1.7.1",
40
+ "jb-popover": ">=1.12.0",
41
41
  "jb-core":">=0.27.2"
42
42
  },
43
43
  "devDependencies": {