@haiilo/catalyst 1.0.2 → 1.1.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.
Files changed (47) hide show
  1. package/dist/catalyst/catalyst.css +1 -1
  2. package/dist/catalyst/catalyst.esm.js +1 -1
  3. package/dist/catalyst/catalyst.esm.js.map +1 -1
  4. package/dist/catalyst/p-78b3fc17.entry.js +10 -0
  5. package/dist/catalyst/p-78b3fc17.entry.js.map +1 -0
  6. package/dist/catalyst/scss/utils/_sizing.mixins.scss +1 -1
  7. package/dist/cjs/cat-alert_23.cjs.entry.js +299 -120
  8. package/dist/cjs/cat-alert_23.cjs.entry.js.map +1 -1
  9. package/dist/cjs/catalyst.cjs.js +1 -1
  10. package/dist/cjs/loader.cjs.js +1 -1
  11. package/dist/collection/components/cat-alert/cat-alert.css +13 -19
  12. package/dist/collection/components/cat-alert/cat-alert.js +17 -18
  13. package/dist/collection/components/cat-alert/cat-alert.js.map +1 -1
  14. package/dist/collection/components/cat-checkbox/cat-checkbox.css +1 -1
  15. package/dist/collection/components/cat-select/cat-select.css +1 -1
  16. package/dist/collection/components/cat-select/cat-select.js +290 -94
  17. package/dist/collection/components/cat-select/cat-select.js.map +1 -1
  18. package/dist/collection/components/cat-select-demo/cat-select-demo.js +43 -30
  19. package/dist/collection/components/cat-select-demo/cat-select-demo.js.map +1 -1
  20. package/dist/collection/components/cat-tooltip/cat-tooltip.css +26 -2
  21. package/dist/collection/components/cat-tooltip/cat-tooltip.js +51 -3
  22. package/dist/collection/components/cat-tooltip/cat-tooltip.js.map +1 -1
  23. package/dist/collection/index.js.map +1 -1
  24. package/dist/collection/scss/utils/_sizing.mixins.scss +1 -1
  25. package/dist/components/cat-alert.js +14 -12
  26. package/dist/components/cat-alert.js.map +1 -1
  27. package/dist/components/cat-checkbox2.js +1 -1
  28. package/dist/components/cat-checkbox2.js.map +1 -1
  29. package/dist/components/cat-select-demo.js +33 -22
  30. package/dist/components/cat-select-demo.js.map +1 -1
  31. package/dist/components/cat-select2.js +237 -81
  32. package/dist/components/cat-select2.js.map +1 -1
  33. package/dist/components/cat-tooltip.js +17 -3
  34. package/dist/components/cat-tooltip.js.map +1 -1
  35. package/dist/esm/cat-alert_23.entry.js +300 -121
  36. package/dist/esm/cat-alert_23.entry.js.map +1 -1
  37. package/dist/esm/catalyst.js +1 -1
  38. package/dist/esm/loader.js +1 -1
  39. package/dist/types/components/cat-alert/cat-alert.d.ts +3 -2
  40. package/dist/types/components/cat-select/cat-select.d.ts +32 -1
  41. package/dist/types/components/cat-select-demo/cat-select-demo.d.ts +3 -0
  42. package/dist/types/components/cat-tooltip/cat-tooltip.d.ts +8 -0
  43. package/dist/types/components.d.ts +37 -5
  44. package/dist/types/index.d.ts +1 -1
  45. package/package.json +2 -2
  46. package/dist/catalyst/p-a2ddc7fa.entry.js +0 -10
  47. package/dist/catalyst/p-a2ddc7fa.entry.js.map +0 -1
@@ -504,7 +504,7 @@ var autosizeInput = function (element, options) {
504
504
  }
505
505
  };
506
506
 
507
- const catSelectCss = ".hint-section{display:flex;gap:0.5rem;flex-direction:column}.hint-section .input-hint,.hint-section ::slotted([slot=hint]){font-size:0.875rem;line-height:1rem;font-weight:var(--cat-font-weight-body, 400);margin:0 !important}:host-context(.cat-error) .hint-section{color:#d9340d}:host{display:flex;flex-direction:column;gap:0.5rem;position:relative;margin-bottom:1rem}:host([hidden]){display:none}label{align-self:flex-start}label.hidden{position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important}.input-optional{margin-left:0.25rem;font-size:0.75rem;line-height:1rem;font-weight:var(--cat-font-weight-body, 400);color:rgb(var(--cat-font-color-muted, 105, 118, 135))}.select-wrapper{display:flex;align-items:flex-start;background:white;border-radius:0.25rem;box-shadow:0 0 0 1px #d7dbe0;transition:box-shadow 0.13s linear;padding:0.25rem}.select-wrapper:not(.select-disabled):hover{box-shadow:0 0 0 2px #d7dbe0}.select-wrapper:not(.select-disabled):focus-within{outline:2px solid rgb(var(--cat-border-color-focus, 0, 113, 255))}:host(.cat-error) .select-wrapper{box-shadow:0 0 0 1px #d9340d}:host(.cat-error) .select-wrapper:not(.input-disabled):hover{box-shadow:0 0 0 2px #d9340d}.select-disabled{background:#f8f8fb;cursor:not-allowed;color:rgb(var(--cat-font-color-muted, 105, 118, 135));pointer-events:none}.select-wrapper-inner{display:flex;flex:1 1 auto;flex-wrap:wrap;align-items:center;gap:0.25rem;min-width:0}.select-wrapper-inner>cat-avatar{padding-left:0.25rem}.select-wrapper-inner cat-avatar{--cat-avatar-size:1.25rem}.select-input{font:inherit;background:none;border:none;outline:none;padding:0.375rem 0.5rem;flex:1 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.select-disabled .select-input{cursor:inherit}.select-pills{display:contents}.pill{display:inline-flex;align-items:center;gap:0.5rem;padding:0.25rem 0.5rem;background:#ebecf0;border-radius:0.125rem;white-space:nowrap;min-width:0}.pill>span{overflow:hidden;text-overflow:ellipsis}.pill>cat-button{margin-right:-0.25rem;margin-left:-0.25rem}.select-btn{transition:transform 0.13s linear}.select-btn::part(button){outline:none}cat-spinner{padding:0.375rem}.select-btn-open{transform:rotate(180deg)}.select-dropdown{position:absolute;right:0;background:white;display:none;overflow:auto;box-shadow:0 1px 4px 0 rgba(16, 29, 48, 0.2);border-radius:0.25rem;z-index:100}.select-options-wrapper{max-height:16rem;width:100%}.select-empty{margin:1rem 0;padding:0 1.25rem}.select-options{list-style-type:none;margin:0;padding:0.5rem 0}.select-options cat-checkbox,.select-options .select-option-single{margin:0;padding:0.5rem 1rem}.select-option-inner{display:flex;gap:0.5rem;--cat-avatar-size:1.25rem}.select-option-single{cursor:pointer}.select-input-transparent-caret{caret-color:transparent}.select-option-empty,.select-option-loading{padding:0.5rem 1rem}.select-option:hover{background-color:rgba(105, 118, 135, 0.05)}.select-option-active{outline:2px solid rgb(var(--cat-border-color-focus, 0, 113, 255));outline-offset:-2px}.select-option-label{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}.select-option-description{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;color:rgb(var(--cat-font-color-muted, 105, 118, 135))}";
507
+ const catSelectCss = ".hint-section{display:flex;gap:0.5rem;flex-direction:column}.hint-section .input-hint,.hint-section ::slotted([slot=hint]){font-size:0.875rem;line-height:1rem;font-weight:var(--cat-font-weight-body, 400);margin:0 !important}:host-context(.cat-error) .hint-section{color:#d9340d}:host{display:flex;flex-direction:column;gap:0.5rem;position:relative;margin-bottom:1rem}:host([hidden]){display:none}label{align-self:flex-start}label.hidden{position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important}.input-optional{margin-left:0.25rem;font-size:0.75rem;line-height:1rem;font-weight:var(--cat-font-weight-body, 400);color:rgb(var(--cat-font-color-muted, 105, 118, 135))}.select-wrapper{display:flex;align-items:flex-start;background:white;border-radius:0.25rem;box-shadow:0 0 0 1px #d7dbe0;transition:box-shadow 0.13s linear;padding:0.25rem}.select-wrapper:not(.select-disabled):hover{box-shadow:0 0 0 2px #d7dbe0}.select-wrapper:not(.select-disabled):focus-within{outline:2px solid rgb(var(--cat-border-color-focus, 0, 113, 255))}:host(.cat-error) .select-wrapper{box-shadow:0 0 0 1px #d9340d}:host(.cat-error) .select-wrapper:not(.input-disabled):hover{box-shadow:0 0 0 2px #d9340d}.select-disabled{background:#f8f8fb;cursor:not-allowed;color:rgb(var(--cat-font-color-muted, 105, 118, 135));pointer-events:none}.select-wrapper-inner{display:flex;flex:1 1 auto;flex-wrap:wrap;align-items:center;gap:0.25rem;min-width:0}.select-wrapper-inner>cat-avatar{padding-left:0.25rem}.select-wrapper-inner cat-avatar{--cat-avatar-size:1.25rem}.select-input{font:inherit;background:none;border:none;outline:none;padding:0.375rem 0.5rem;flex:1 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.select-disabled .select-input{cursor:inherit}.select-pills{display:contents}.pill{display:inline-flex;align-items:center;gap:0.5rem;padding:0.25rem 0.5rem;background:#f2f4f7;border-radius:0.125rem;white-space:nowrap;min-width:0}.pill>span{overflow:hidden;text-overflow:ellipsis}.pill>cat-button{margin-right:-0.25rem;margin-left:-0.25rem}.select-btn{transition:transform 0.13s linear}.select-btn::part(button){outline:none}cat-spinner{padding:0.375rem}.select-btn-open{transform:rotate(180deg)}.select-dropdown{position:absolute;right:0;background:white;display:none;overflow:auto;box-shadow:0 1px 4px 0 rgba(16, 29, 48, 0.2);border-radius:0.25rem;z-index:100}.select-options-wrapper{max-height:16rem;width:100%}.select-empty{margin:1rem 0;padding:0 1.25rem}.select-options{list-style-type:none;margin:0;padding:0.5rem 0}.select-options cat-checkbox,.select-options .select-option-single{margin:0;padding:0.5rem 1rem}.select-option-inner{display:flex;gap:0.5rem;--cat-avatar-size:1.25rem}.select-option-single{cursor:pointer}.select-input-transparent-caret{caret-color:transparent}.select-option-empty,.select-option-loading{padding:0.5rem 1rem}.select-option:hover{background-color:rgba(105, 118, 135, 0.05)}.select-option-active{outline:2px solid rgb(var(--cat-border-color-focus, 0, 113, 255));outline-offset:-2px}.select-option-label{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}.select-option-description{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;color:rgb(var(--cat-font-color-muted, 105, 118, 135))}";
508
508
 
509
509
  const INIT_STATE = {
510
510
  term: '',
@@ -568,6 +568,10 @@ const CatSelect = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
568
568
  * Whether the select should show a clear button.
569
569
  */
570
570
  this.clearable = false;
571
+ /**
572
+ * Whether the select should add new items.
573
+ */
574
+ this.tags = false;
571
575
  }
572
576
  onConnectorChange(connector) {
573
577
  this.reset(connector);
@@ -587,11 +591,25 @@ const CatSelect = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
587
591
  this.hide();
588
592
  }
589
593
  const idsSelected = this.state.selection.map(item => item.item.id);
590
- if (this.multiple) {
591
- this.value = idsSelected;
594
+ if (!this.tags) {
595
+ if (this.multiple) {
596
+ this.value = idsSelected;
597
+ }
598
+ else {
599
+ this.value = idsSelected.length ? idsSelected[0] : '';
600
+ }
592
601
  }
593
602
  else {
594
- this.value = idsSelected.length ? idsSelected[0] : '';
603
+ const ids = idsSelected.filter(id => !id.startsWith(`select-${this.id}-tag`));
604
+ const tags = this.state.selection
605
+ .filter(item => item.item.id.startsWith(`select-${this.id}-tag`))
606
+ .map(item => item.render.label);
607
+ if (this.multiple) {
608
+ this.value = { ids, tags };
609
+ }
610
+ else {
611
+ this.value = { id: ids.length ? ids[0] : '', tag: tags.length ? tags[0] : '' };
612
+ }
595
613
  }
596
614
  this.catChange.emit();
597
615
  }
@@ -612,7 +630,12 @@ const CatSelect = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
612
630
  }
613
631
  onBlur(event) {
614
632
  if (!this.multiple && this.state.activeOptionIndex >= 0) {
615
- this.select(this.state.options[this.state.activeOptionIndex]);
633
+ if (this.tags && this.state.options[this.state.activeOptionIndex].item.id === `select-${this.id}-option-tag`) {
634
+ this.createTag(this.state.term);
635
+ }
636
+ else {
637
+ this.select(this.state.options[this.state.activeOptionIndex]);
638
+ }
616
639
  }
617
640
  this.hide();
618
641
  this.patchState({ activeSelectionIndex: -1 });
@@ -624,8 +647,19 @@ const CatSelect = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
624
647
  if (['ArrowDown', 'ArrowUp', 'ArrowLeft', 'ArrowRight'].includes(event.key)) {
625
648
  this.onArrowKeyDown(event);
626
649
  }
627
- else if (['Enter', ' '].includes(event.key)) {
628
- if (isInputFocused && this.state.activeOptionIndex >= 0) {
650
+ else if (['Enter', ' '].includes(event.key) && isInputFocused) {
651
+ if (this.tags &&
652
+ this.state.activeOptionIndex === 0 &&
653
+ this.state.options[0].item.id === `select-${this.id}-option-tag`) {
654
+ event.preventDefault();
655
+ if (this.multiple) {
656
+ this.toggleTag(this.state.options[0]);
657
+ }
658
+ else {
659
+ this.createTag(this.state.options[0].render.label);
660
+ }
661
+ }
662
+ else if (this.state.activeOptionIndex >= 0) {
629
663
  event.preventDefault();
630
664
  if (this.multiple) {
631
665
  this.toggle(this.state.options[this.state.activeOptionIndex]);
@@ -634,6 +668,9 @@ const CatSelect = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
634
668
  this.select(this.state.options[this.state.activeOptionIndex]);
635
669
  }
636
670
  }
671
+ else if (this.tags && event.key === 'Enter' && this.state.activeOptionIndex < 0) {
672
+ this.createTag(this.state.term);
673
+ }
637
674
  }
638
675
  else if (event.key === 'Escape') {
639
676
  this.hide();
@@ -644,11 +681,6 @@ const CatSelect = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
644
681
  if (this.state.activeSelectionIndex >= 0) {
645
682
  this.deselect(this.state.selection[this.state.activeSelectionIndex].item.id);
646
683
  }
647
- else if (this.state.selection.length) {
648
- const selectionClone = [...this.state.selection];
649
- selectionClone.pop();
650
- this.patchState({ selection: selectionClone });
651
- }
652
684
  }
653
685
  }
654
686
  else if (event.key === 'Tab') {
@@ -657,7 +689,12 @@ const CatSelect = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
657
689
  this.patchState({ activeSelectionIndex: -1, activeOptionIndex: -1 });
658
690
  }
659
691
  else if (this.state.activeOptionIndex >= 0) {
660
- this.select(this.state.options[this.state.activeOptionIndex]);
692
+ if (this.tags && this.state.options[this.state.activeOptionIndex].item.id === `select-${this.id}-option-tag`) {
693
+ this.createTag(this.state.term);
694
+ }
695
+ else {
696
+ this.select(this.state.options[this.state.activeOptionIndex]);
697
+ }
661
698
  }
662
699
  }
663
700
  else if (event.key.length === 1) {
@@ -695,12 +732,28 @@ const CatSelect = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
695
732
  this.subscription = this.term$
696
733
  .asObservable()
697
734
  .pipe(debounce(term => (term ? timer(this.debounce) : of(0))), distinctUntilChanged(), tap(() => (number$ = this.more$.pipe(filter(() => !this.state.isLoading), scan(n => n + 1, 0), startWith(0)))), tap(() => this.patchState({ options: [] })), switchMap(term => number$.pipe(tap(() => this.patchState({ isLoading: true })), switchMap(number => this.connectorSafe.retrieve(term, number)), tap(page => this.patchState({ isLoading: false, totalElements: page.totalElements })), takeWhile(page => !page.last, true), scan((items, page) => [...items, ...page.content], []))))
698
- .subscribe(items => this.patchState({
699
- options: items === null || items === void 0 ? void 0 : items.map(item => ({
735
+ .subscribe(items => {
736
+ var _a;
737
+ const options = items === null || items === void 0 ? void 0 : items.map(item => ({
700
738
  item,
701
739
  render: this.connectorSafe.render(item)
702
- }))
703
- }));
740
+ }));
741
+ if (this.tags &&
742
+ this.state.term.trim().length &&
743
+ !options.find(value1 => value1.render.label.toLowerCase() === this.state.term.toLowerCase())) {
744
+ let label;
745
+ if (this.isAlreadyCreated(this.state.term)) {
746
+ label = (_a = this.state.selection.find(item => item.render.label.toLowerCase() === this.state.term.toLowerCase())) === null || _a === void 0 ? void 0 : _a.render.label;
747
+ }
748
+ options.unshift({
749
+ item: { id: `select-${this.id}-option-tag` },
750
+ render: { label: label ? label : this.state.term }
751
+ });
752
+ }
753
+ this.patchState({
754
+ options
755
+ });
756
+ });
704
757
  }
705
758
  render() {
706
759
  return (h(Host, null, (this.hasSlottedLabel || this.label) && (h("label", { htmlFor: this.id, class: { hidden: this.labelHidden } }, h("span", { part: "label" }, (this.hasSlottedLabel && h("slot", { name: "label" })) || this.label, !this.required && (h("span", { class: "input-optional", "aria-hidden": "true" }, "(", this.i18n.t('input.optional'), ")"))))), h("div", { class: { 'select-wrapper': true, 'select-disabled': this.disabled }, ref: el => (this.trigger = el), id: this.id, role: "combobox", "aria-expanded": this.state.isOpen || this.isPillboxActive(), "aria-controls": this.isPillboxActive() ? `select-pillbox-${this.id}` : `select-listbox-${this.id}`, "aria-required": this.required, "aria-activedescendant": this.activeDescendant, onClick: e => this.onClick(e) }, h("div", { class: "select-wrapper-inner" }, this.multiple && this.state.selection.length ? (h("div", { id: `select-pillbox-${this.id}`, role: "listbox", "aria-orientation": "horizontal", class: "select-pills" }, this.state.selection.map((item, i) => (h("span", { class: {
@@ -710,16 +763,35 @@ const CatSelect = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
710
763
  }, role: "option", "aria-selected": "true", id: `select-${this.id}-selection-${i}` }, item.render.avatar ? (h("cat-avatar", { label: item.render.label, round: item.render.avatar.round, src: item.render.avatar.src, initials: '' })) : null, h("span", null, item.render.label), !this.disabled && (h("cat-button", { size: "xs", variant: "text", icon: "16-cross", iconOnly: true, a11yLabel: this.i18n.t('select.deselect'), onClick: () => this.deselect(item.item.id), tabIndex: -1 }))))))) : this.state.selection.length && this.state.selection[0].render.avatar ? (h("cat-avatar", { label: this.state.selection[0].render.label, round: this.state.selection[0].render.avatar.round, src: this.state.selection[0].render.avatar.src, initials: '' })) : null, h("input", { class: "select-input", ref: el => (this.input = el), "aria-controls": this.isPillboxActive() ? `select-pillbox-${this.id}` : `select-listbox-${this.id}`, "aria-activedescendant": this.activeDescendant, onInput: () => this.onInput(), value: !this.multiple ? this.state.term : undefined, placeholder: this.placeholder, disabled: this.disabled || this.state.isResolving })), this.state.isResolving && h("cat-spinner", null), (this.state.selection.length || this.state.term.length) &&
711
764
  !this.disabled &&
712
765
  !this.state.isResolving &&
713
- this.clearable ? (h("cat-button", { id: `select-clear-btn-${this.id}`, iconOnly: true, icon: "cross-circle-outlined", variant: "text", size: "s", a11yLabel: this.i18n.t('input.clear'), onClick: () => this.clear() })) : null, !this.state.isResolving && (h("cat-button", { iconOnly: true, icon: "chevron-down-outlined", class: { 'select-btn': true, 'select-btn-open': this.state.isOpen }, variant: "text", size: "s", a11yLabel: this.state.isOpen ? this.i18n.t('select.close') : this.i18n.t('select.open'), "aria-controls": `select-listbox-${this.id}`, "aria-expanded": this.state.isOpen, tabIndex: -1, disabled: this.disabled || this.state.isResolving }))), this.hintSection, h("div", { class: "select-dropdown", ref: el => (this.dropdown = el), style: { display: this.state.isOpen ? 'block' : undefined } }, this.state.isOpen && (h("cat-scrollable", { class: "select-options-wrapper", scrolledBuffer: 56, noOverflowX: true, noOverscroll: true, noScrolledInit: true, onScrolledBottom: () => this.more$.next() }, h("ul", { class: "select-options", role: "listbox", "aria-multiselectable": this.multiple, "aria-setsize": this.state.totalElements, id: `select-listbox-${this.id}` }, this.state.options.map((item, i) => (h("li", { role: "option", class: "select-option", id: `select-${this.id}-option-${i}`, "aria-selected": this.isSelected(item.item.id) ? 'true' : 'false' }, this.multiple ? (h("cat-checkbox", { class: { 'select-option-active': this.state.activeOptionIndex === i }, checked: this.isSelected(item.item.id), tabIndex: -1, labelLeft: true, onFocus: () => { var _a; return (_a = this.input) === null || _a === void 0 ? void 0 : _a.focus(); }, onCatChange: e => {
714
- this.toggle(item);
715
- e.stopPropagation();
716
- } }, h("span", { slot: "label", class: "select-option-inner" }, item.render.avatar ? (h("cat-avatar", { label: item.render.label, round: item.render.avatar.round, src: item.render.avatar.src, initials: '' })) : null, h("span", { class: "select-option-text" }, h("span", { class: "select-option-label" }, item.render.label), h("span", { class: "select-option-description" }, item.render.description))))) : (h("div", { class: {
717
- 'select-option-inner': true,
718
- 'select-option-single': true,
719
- 'select-option-active': this.state.activeOptionIndex === i
720
- }, onFocus: () => { var _a; return (_a = this.input) === null || _a === void 0 ? void 0 : _a.focus(); }, onClick: () => this.select(item), tabIndex: -1 }, item.render.avatar ? (h("cat-avatar", { label: item.render.label, round: item.render.avatar.round, src: item.render.avatar.src, initials: '' })) : null, h("span", { class: "select-option-text" }, h("span", { class: "select-option-label" }, item.render.label), h("span", { class: "select-option-description" }, item.render.description))))))), this.state.isLoading
766
+ this.clearable ? (h("cat-button", { id: `select-clear-btn-${this.id}`, iconOnly: true, icon: "cross-circle-outlined", variant: "text", size: "s", a11yLabel: this.i18n.t('input.clear'), onClick: () => this.clear() })) : null, !this.state.isResolving && (h("cat-button", { iconOnly: true, icon: "chevron-down-outlined", class: { 'select-btn': true, 'select-btn-open': this.state.isOpen }, variant: "text", size: "s", a11yLabel: this.state.isOpen ? this.i18n.t('select.close') : this.i18n.t('select.open'), "aria-controls": `select-listbox-${this.id}`, "aria-expanded": this.state.isOpen, tabIndex: -1, disabled: this.disabled || this.state.isResolving }))), this.hintSection, h("div", { class: "select-dropdown", ref: el => (this.dropdown = el), style: { display: this.state.isOpen ? 'block' : undefined } }, this.state.isOpen && (h("cat-scrollable", { class: "select-options-wrapper", scrolledBuffer: 56, noOverflowX: true, noOverscroll: true, noScrolledInit: true, onScrolledBottom: () => this.more$.next() }, h("ul", { class: "select-options", role: "listbox", "aria-multiselectable": this.multiple, "aria-setsize": this.state.totalElements, id: `select-listbox-${this.id}` }, this.optionsList, this.state.isLoading
721
767
  ? Array.from(Array(CatSelect.SKELETON_COUNT)).map(() => (h("li", { class: "select-option-loading" }, h("cat-skeleton", { variant: "body", lines: 1 }), h("cat-skeleton", { variant: "body", lines: 1 }))))
722
- : !this.state.options.length && h("li", { class: "select-option-empty" }, this.i18n.t('select.empty'))))))));
768
+ : !this.state.options.length &&
769
+ !this.tags && h("li", { class: "select-option-empty" }, this.i18n.t('select.empty'))))))));
770
+ }
771
+ get optionsList() {
772
+ return this.state.options.map((item, i) => {
773
+ const isTagOption = this.tags && item.item.id === `select-${this.id}-option-tag`;
774
+ const getAriaSelected = () => {
775
+ if (isTagOption) {
776
+ return this.isAlreadyCreated(item.render.label) ? 'true' : 'false';
777
+ }
778
+ return this.isSelected(item.item.id) ? 'true' : 'false';
779
+ };
780
+ const getLabel = () => {
781
+ if (isTagOption) {
782
+ return item.render.label + this.tagTextHelp;
783
+ }
784
+ return item.render.label;
785
+ };
786
+ return (h("li", { role: "option", class: "select-option", id: `select-${this.id}-option-${i}`, "aria-selected": getAriaSelected() }, this.multiple ? (h("cat-checkbox", { class: { 'select-option-active': this.state.activeOptionIndex === i }, checked: !isTagOption ? this.isSelected(item.item.id) : this.isAlreadyCreated(item.render.label), tabIndex: -1, labelLeft: true, onFocus: () => { var _a; return (_a = this.input) === null || _a === void 0 ? void 0 : _a.focus(); }, onCatChange: e => {
787
+ !isTagOption ? this.toggle(item) : this.toggleTag(item);
788
+ e.stopPropagation();
789
+ } }, h("span", { slot: "label", class: "select-option-inner" }, item.render.avatar ? (h("cat-avatar", { label: item.render.label, round: item.render.avatar.round, src: item.render.avatar.src, initials: '' })) : null, h("span", { class: "select-option-text" }, h("span", { class: "select-option-label" }, getLabel()), h("span", { class: "select-option-description" }, item.render.description))))) : (h("div", { class: {
790
+ 'select-option-inner': true,
791
+ 'select-option-single': true,
792
+ 'select-option-active': this.state.activeOptionIndex === i
793
+ }, onFocus: () => { var _a; return (_a = this.input) === null || _a === void 0 ? void 0 : _a.focus(); }, onClick: () => (isTagOption ? this.createTag(item.render.label) : this.select(item)), tabIndex: -1 }, item.render.avatar ? (h("cat-avatar", { label: item.render.label, round: item.render.avatar.round, src: item.render.avatar.src, initials: '' })) : null, h("span", { class: "select-option-text" }, h("span", { class: "select-option-label" }, getLabel()), h("span", { class: "select-option-description" }, item.render.description))))));
794
+ });
723
795
  }
724
796
  get hintSection() {
725
797
  const hasSlottedHint = !!this.hostElement.querySelector('[slot="hint"]');
@@ -732,21 +804,27 @@ const CatSelect = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
732
804
  throw new Error('CatSelectConnector not set');
733
805
  }
734
806
  resolve() {
735
- var _a;
736
807
  this.patchState({ isResolving: true });
737
- let ids;
738
- if (this.multiple) {
739
- ids = this.value;
740
- }
741
- else {
742
- ids = [this.value];
808
+ const ids = this.initIds();
809
+ let tags;
810
+ if (this.tags) {
811
+ tags = this.initTags();
743
812
  }
744
- const data$ = ((_a = this.value) === null || _a === void 0 ? void 0 : _a.length) ? this.connectorSafe.resolve(ids).pipe(first()) : of([]);
745
- data$.pipe(catchError(() => of([]))).subscribe(items => this.patchState({
746
- isResolving: false,
747
- selection: items === null || items === void 0 ? void 0 : items.map(item => ({ item, render: this.connectorSafe.render(item) })),
748
- term: !this.multiple && items.length ? this.connectorSafe.render(items[0]).label : ''
749
- }));
813
+ const data$ = ids.length ? this.connectorSafe.resolve(ids).pipe(first()) : of([]);
814
+ data$.pipe(catchError(() => of([]))).subscribe(items => {
815
+ const selection = items.length ? items === null || items === void 0 ? void 0 : items.map(item => ({ item, render: this.connectorSafe.render(item) })) : [];
816
+ if (this.tags) {
817
+ tags === null || tags === void 0 ? void 0 : tags.forEach((tag, index) => {
818
+ const item = { id: `select-${this.id}-tag-${index}`, name: tag };
819
+ selection.push({ item, render: { label: item.name } });
820
+ });
821
+ }
822
+ this.patchState({
823
+ isResolving: false,
824
+ selection,
825
+ term: !this.multiple && selection.length ? selection[0].render.label : ''
826
+ });
827
+ });
750
828
  }
751
829
  show() {
752
830
  var _a;
@@ -771,7 +849,6 @@ const CatSelect = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
771
849
  return this.state.selection.findIndex(s => s.item.id === id) >= 0;
772
850
  }
773
851
  select(item) {
774
- var _a;
775
852
  if (!this.isSelected(item.item.id)) {
776
853
  let newSelection;
777
854
  if (this.multiple) {
@@ -782,11 +859,13 @@ const CatSelect = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
782
859
  this.search(item.render.label);
783
860
  }
784
861
  this.patchState({ selection: newSelection });
862
+ if (this.multiple && this.state.term.trim() && this.input) {
863
+ this.patchState({ term: '', activeOptionIndex: -1 });
864
+ this.term$.next('');
865
+ this.input.value = '';
866
+ }
785
867
  }
786
- if (!this.multiple) {
787
- this.hide();
788
- (_a = this.input) === null || _a === void 0 ? void 0 : _a.classList.add('select-input-transparent-caret');
789
- }
868
+ this.setTransparentCaret();
790
869
  }
791
870
  deselect(id) {
792
871
  if (this.isSelected(id)) {
@@ -833,7 +912,12 @@ const CatSelect = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
833
912
  }
834
913
  onInput() {
835
914
  var _a;
836
- this.search(((_a = this.input) === null || _a === void 0 ? void 0 : _a.value) || '');
915
+ this.search(((_a = this.input) === null || _a === void 0 ? void 0 : _a.value.trim()) || '');
916
+ if (!this.multiple && this.state.selection.length) {
917
+ const selectionClone = [...this.state.selection];
918
+ selectionClone.pop();
919
+ this.patchState({ selection: selectionClone });
920
+ }
837
921
  this.show();
838
922
  }
839
923
  update() {
@@ -871,52 +955,122 @@ const CatSelect = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
871
955
  var _a, _b;
872
956
  let preventDefault = false;
873
957
  (_a = this.input) === null || _a === void 0 ? void 0 : _a.focus();
874
- if (event.key === 'ArrowDown') {
875
- preventDefault = true;
876
- this.state.isOpen
877
- ? this.patchState({
878
- activeOptionIndex: Math.min(this.state.activeOptionIndex + 1, this.state.options.length - 1),
879
- activeSelectionIndex: -1
880
- })
881
- : this.show();
882
- }
883
- else if (event.key === 'ArrowUp') {
884
- preventDefault = true;
885
- this.state.activeOptionIndex >= 0
886
- ? this.patchState({
887
- activeOptionIndex: Math.max(this.state.activeOptionIndex - 1, -1),
888
- activeSelectionIndex: -1
889
- })
890
- : this.hide();
891
- }
892
- else if (event.key === 'ArrowLeft') {
893
- if (((_b = this.input) === null || _b === void 0 ? void 0 : _b.selectionStart) === 0) {
958
+ switch (event.key) {
959
+ case 'ArrowDown':
894
960
  preventDefault = true;
895
- let index;
896
- this.state.activeSelectionIndex > 0
897
- ? (index = Math.max(this.state.activeSelectionIndex - 1, -1))
898
- : (index = this.state.selection.length - 1);
899
- this.patchState({ activeSelectionIndex: index, activeOptionIndex: -1 });
900
- }
901
- }
902
- else if (event.key === 'ArrowRight') {
903
- if (this.state.activeSelectionIndex >= 0) {
961
+ this.state.isOpen
962
+ ? this.patchState({
963
+ activeOptionIndex: Math.min(this.state.activeOptionIndex + 1, this.state.options.length - 1),
964
+ activeSelectionIndex: -1
965
+ })
966
+ : this.show();
967
+ break;
968
+ case 'ArrowUp':
904
969
  preventDefault = true;
905
- let index = -1;
906
- if (this.state.activeSelectionIndex < this.state.selection.length - 1) {
907
- index = Math.min(this.state.activeSelectionIndex + 1, this.state.selection.length - 1);
970
+ this.state.activeOptionIndex >= 0
971
+ ? this.patchState({
972
+ activeOptionIndex: Math.max(this.state.activeOptionIndex - 1, -1),
973
+ activeSelectionIndex: -1
974
+ })
975
+ : this.hide();
976
+ break;
977
+ case 'ArrowLeft':
978
+ if (((_b = this.input) === null || _b === void 0 ? void 0 : _b.selectionStart) === 0) {
979
+ preventDefault = true;
980
+ let index;
981
+ this.state.activeSelectionIndex > 0
982
+ ? (index = Math.max(this.state.activeSelectionIndex - 1, -1))
983
+ : (index = this.state.selection.length - 1);
984
+ this.patchState({ activeSelectionIndex: index, activeOptionIndex: -1 });
908
985
  }
909
- else if (!this.state.term) {
910
- index = 0;
986
+ break;
987
+ case 'ArrowRight':
988
+ if (this.state.activeSelectionIndex >= 0) {
989
+ preventDefault = true;
990
+ let index = -1;
991
+ if (this.state.activeSelectionIndex < this.state.selection.length - 1) {
992
+ index = Math.min(this.state.activeSelectionIndex + 1, this.state.selection.length - 1);
993
+ }
994
+ else if (!this.state.term) {
995
+ index = 0;
996
+ }
997
+ this.patchState({ activeSelectionIndex: index, activeOptionIndex: -1 });
911
998
  }
912
- this.patchState({ activeSelectionIndex: index, activeOptionIndex: -1 });
913
- }
914
999
  }
915
1000
  if (preventDefault) {
916
1001
  event.preventDefault();
917
1002
  event.stopPropagation();
918
1003
  }
919
1004
  }
1005
+ get tagTextHelp() {
1006
+ return this.tagHint && !this.isAlreadyCreated(this.state.term) ? ' (' + this.tagHint + ')' : '';
1007
+ }
1008
+ isAlreadyCreated(term) {
1009
+ return this.state.selection.findIndex(item => item.render.label.toLowerCase() === term.toLowerCase()) >= 0;
1010
+ }
1011
+ createTag(term) {
1012
+ if (term.trim().length && !this.isAlreadyCreated(term)) {
1013
+ const value = this.value;
1014
+ const tags = value === null || value === void 0 ? void 0 : value.tags;
1015
+ const tag = { id: `select-${this.id}-tag-${tags ? tags.length : 0}`, name: term };
1016
+ this.select({ item: tag, render: { label: tag.name } });
1017
+ }
1018
+ this.setTransparentCaret();
1019
+ }
1020
+ initIds() {
1021
+ let ids = [];
1022
+ if (this.value) {
1023
+ if (!this.tags) {
1024
+ if (this.multiple) {
1025
+ ids = this.value;
1026
+ }
1027
+ else {
1028
+ ids = [this.value];
1029
+ }
1030
+ }
1031
+ else {
1032
+ if (this.multiple) {
1033
+ const value = this.value;
1034
+ ids = value.ids ? value.ids : [];
1035
+ }
1036
+ else {
1037
+ const value = this.value;
1038
+ ids = value.id ? [value.id] : [];
1039
+ }
1040
+ }
1041
+ }
1042
+ return ids;
1043
+ }
1044
+ initTags() {
1045
+ let tags = [];
1046
+ if (this.value) {
1047
+ if (this.multiple) {
1048
+ const value = this.value;
1049
+ tags = value.tags ? value.tags : [];
1050
+ }
1051
+ else {
1052
+ const value = this.value;
1053
+ tags = value.tag ? [value.tag] : [];
1054
+ }
1055
+ }
1056
+ return tags;
1057
+ }
1058
+ toggleTag(item) {
1059
+ this.isAlreadyCreated(item.render.label) ? this.removeTag(item.render.label) : this.createTag(item.render.label);
1060
+ }
1061
+ removeTag(label) {
1062
+ if (this.isAlreadyCreated(label)) {
1063
+ const item = this.state.selection.find(item => item.render.label.toLowerCase() === label.toLowerCase());
1064
+ item && this.deselect(item.item.id);
1065
+ }
1066
+ }
1067
+ setTransparentCaret() {
1068
+ var _a;
1069
+ if (!this.multiple) {
1070
+ this.hide();
1071
+ (_a = this.input) === null || _a === void 0 ? void 0 : _a.classList.add('select-input-transparent-caret');
1072
+ }
1073
+ }
920
1074
  get hostElement() { return this; }
921
1075
  static get watchers() { return {
922
1076
  "connector": ["onConnectorChange"],
@@ -936,6 +1090,8 @@ const CatSelect = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
936
1090
  "labelHidden": [4, "label-hidden"],
937
1091
  "required": [4],
938
1092
  "clearable": [4],
1093
+ "tags": [4],
1094
+ "tagHint": [1, "tag-hint"],
939
1095
  "connector": [32],
940
1096
  "state": [32],
941
1097
  "hasSlottedLabel": [32],