@kodaris/krubble-components 1.0.69 → 1.0.70

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.
@@ -481,18 +481,34 @@
481
481
  * @attr icon-position
482
482
  */
483
483
  this.iconPosition = 'left';
484
+ /**
485
+ * When true and options are provided, renders as a split button with
486
+ * separate primary action and dropdown trigger zones.
487
+ */
488
+ this.split = false;
484
489
  this._state = 'idle';
485
490
  this._stateText = '';
486
491
  this._dropdownOpened = false;
487
492
  this._handleHostClick = (e) => {
493
+ if (this.split && this.options.length) {
494
+ return;
495
+ }
488
496
  if (this.options.length) {
489
497
  e.stopPropagation();
490
498
  this._toggleDropdown();
491
499
  }
492
500
  };
493
501
  this._handleKeydown = (e) => {
502
+ if (e.key === 'Escape' && this._dropdownOpened) {
503
+ this._dropdownOpened = false;
504
+ return;
505
+ }
494
506
  if (e.key === 'Enter' || e.key === ' ') {
495
507
  e.preventDefault();
508
+ if (this.split && this.options.length) {
509
+ this.dispatchEvent(new MouseEvent('click', { bubbles: true, composed: true }));
510
+ return;
511
+ }
496
512
  if (this.options.length) {
497
513
  this._toggleDropdown();
498
514
  }
@@ -500,8 +516,11 @@
500
516
  this.click();
501
517
  }
502
518
  }
503
- if (e.key === 'Escape' && this._dropdownOpened) {
504
- this._dropdownOpened = false;
519
+ if (this.split && this.options.length && e.key === 'ArrowDown') {
520
+ e.preventDefault();
521
+ if (!this._dropdownOpened) {
522
+ this._toggleDropdown();
523
+ }
505
524
  }
506
525
  };
507
526
  this._handleClickOutside = (e) => {
@@ -524,6 +543,20 @@
524
543
  this.removeEventListener('click', this._handleHostClick);
525
544
  document.removeEventListener('click', this._handleClickOutside);
526
545
  }
546
+ _handleSplitPrimaryClick(e) {
547
+ e.stopPropagation();
548
+ if (this._dropdownOpened) {
549
+ this._dropdownOpened = false;
550
+ }
551
+ this.dispatchEvent(new MouseEvent('click', {
552
+ bubbles: true,
553
+ composed: true,
554
+ }));
555
+ }
556
+ _handleSplitTriggerClick(e) {
557
+ e.stopPropagation();
558
+ this._toggleDropdown();
559
+ }
527
560
  _toggleDropdown() {
528
561
  this._dropdownOpened = !this._dropdownOpened;
529
562
  if (this._dropdownOpened) {
@@ -636,8 +669,38 @@
636
669
  this.classList.toggle(`kr-button--${this.color}`, true);
637
670
  this.classList.toggle('kr-button--small', this.size === 'small');
638
671
  this.classList.toggle('kr-button--large', this.size === 'large');
672
+ this.classList.toggle('kr-button--split', this.split && !!this.options.length);
639
673
  }
640
674
  render() {
675
+ if (this.split && this.options.length) {
676
+ return b `
677
+ <div class="split-primary" @click=${(e) => this._handleSplitPrimaryClick(e)}>
678
+ <span class="content">
679
+ <slot name="icon"></slot>
680
+ <slot></slot>
681
+ </span>
682
+ ${this._state !== 'idle'
683
+ ? b `<span class="state-overlay">
684
+ ${this._state === 'loading'
685
+ ? b `<span class="spinner"></span>`
686
+ : this._stateText}
687
+ </span>`
688
+ : A}
689
+ </div>
690
+ <div class="split-divider"></div>
691
+ <div class="split-trigger" @click=${(e) => this._handleSplitTriggerClick(e)}>
692
+ <svg class="caret" xmlns="http://www.w3.org/2000/svg" height="20" width="20" viewBox="0 0 24 24" fill="currentColor"><path d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z"/></svg>
693
+ </div>
694
+ <div class="dropdown ${this._dropdownOpened ? 'dropdown--opened' : ''}">
695
+ ${this.options.map(option => b `
696
+ <button
697
+ class="dropdown-item"
698
+ @click=${(e) => this._handleOptionClick(option, e)}
699
+ >${option.label}</button>
700
+ `)}
701
+ </div>
702
+ `;
703
+ }
641
704
  const content = b `
642
705
  <span class="content">
643
706
  <slot name="icon"></slot>
@@ -937,6 +1000,154 @@
937
1000
  width: 22px;
938
1001
  height: 22px;
939
1002
  }
1003
+
1004
+ /* ========================
1005
+ Split Button
1006
+ ======================== */
1007
+
1008
+ :host(.kr-button--split) {
1009
+ padding: 0;
1010
+ pointer-events: none;
1011
+ }
1012
+
1013
+ .split-primary,
1014
+ .split-trigger {
1015
+ display: inline-flex;
1016
+ align-items: center;
1017
+ justify-content: center;
1018
+ height: 100%;
1019
+ cursor: pointer;
1020
+ pointer-events: auto;
1021
+ }
1022
+
1023
+ .split-primary {
1024
+ padding: 0 16px 0 22px;
1025
+ border-radius: 20px 0 0 20px;
1026
+ position: relative;
1027
+ flex: 1;
1028
+ }
1029
+
1030
+ .split-trigger {
1031
+ padding: 0 14px 0 8px;
1032
+ border-radius: 0 20px 20px 0;
1033
+ }
1034
+
1035
+ .split-trigger .caret {
1036
+ margin: 0;
1037
+ }
1038
+
1039
+ .split-divider {
1040
+ width: 1px;
1041
+ height: 100%;
1042
+ flex-shrink: 0;
1043
+ }
1044
+
1045
+ .dropdown {
1046
+ pointer-events: auto;
1047
+ }
1048
+
1049
+ /* Split: zone hover — flat primary */
1050
+ :host(.kr-button--flat.kr-button--primary) .split-primary:hover,
1051
+ :host(.kr-button--flat.kr-button--primary) .split-trigger:hover {
1052
+ background: #0e1f35;
1053
+ }
1054
+
1055
+ /* Split: zone hover — flat secondary */
1056
+ :host(.kr-button--flat.kr-button--secondary) .split-primary:hover,
1057
+ :host(.kr-button--flat.kr-button--secondary) .split-trigger:hover {
1058
+ background: #e5e7eb;
1059
+ }
1060
+
1061
+ /* Split: zone hover — flat danger */
1062
+ :host(.kr-button--flat.kr-button--danger) .split-primary:hover,
1063
+ :host(.kr-button--flat.kr-button--danger) .split-trigger:hover {
1064
+ background: #b91c1c;
1065
+ }
1066
+
1067
+ /* Split: zone hover — outline primary */
1068
+ :host(.kr-button--outline.kr-button--primary) .split-primary:hover,
1069
+ :host(.kr-button--outline.kr-button--primary) .split-trigger:hover {
1070
+ background: rgba(22, 48, 82, 0.05);
1071
+ }
1072
+
1073
+ /* Split: zone hover — outline secondary */
1074
+ :host(.kr-button--outline.kr-button--secondary) .split-primary:hover,
1075
+ :host(.kr-button--outline.kr-button--secondary) .split-trigger:hover {
1076
+ background: #f9fafb;
1077
+ }
1078
+
1079
+ /* Split: zone hover — outline danger */
1080
+ :host(.kr-button--outline.kr-button--danger) .split-primary:hover,
1081
+ :host(.kr-button--outline.kr-button--danger) .split-trigger:hover {
1082
+ background: rgba(219, 38, 39, 0.05);
1083
+ }
1084
+
1085
+ /* Split: divider colors — flat variants */
1086
+ :host(.kr-button--flat.kr-button--primary) .split-divider {
1087
+ background: rgba(255, 255, 255, 0.3);
1088
+ }
1089
+
1090
+ :host(.kr-button--flat.kr-button--secondary) .split-divider {
1091
+ background: rgba(0, 0, 0, 0.15);
1092
+ }
1093
+
1094
+ :host(.kr-button--flat.kr-button--danger) .split-divider {
1095
+ background: rgba(255, 255, 255, 0.3);
1096
+ }
1097
+
1098
+ /* Split: divider colors — outline variants */
1099
+ :host(.kr-button--outline.kr-button--primary) .split-divider {
1100
+ background: #163052;
1101
+ }
1102
+
1103
+ :host(.kr-button--outline.kr-button--secondary) .split-divider {
1104
+ background: #d1d5db;
1105
+ }
1106
+
1107
+ :host(.kr-button--outline.kr-button--danger) .split-divider {
1108
+ background: rgb(219, 38, 39);
1109
+ }
1110
+
1111
+ /* Split: size small */
1112
+ :host(.kr-button--split.kr-button--small) .split-primary {
1113
+ padding: 0 12px 0 16px;
1114
+ }
1115
+
1116
+ :host(.kr-button--split.kr-button--small) .split-trigger {
1117
+ padding: 0 10px;
1118
+ }
1119
+
1120
+ /* Split: size large */
1121
+ :host(.kr-button--split.kr-button--large) .split-primary {
1122
+ padding: 0 18px 0 24px;
1123
+ border-radius: 30px 0 0 30px;
1124
+ }
1125
+
1126
+ :host(.kr-button--split.kr-button--large) .split-trigger {
1127
+ padding: 0 16px;
1128
+ border-radius: 0 30px 30px 0;
1129
+ }
1130
+
1131
+ /* Split: disabled */
1132
+ :host([disabled]) .split-primary,
1133
+ :host([disabled]) .split-trigger {
1134
+ cursor: not-allowed;
1135
+ pointer-events: none;
1136
+ }
1137
+
1138
+ /* Split: loading/success/error — overlay in primary zone only */
1139
+ :host(.kr-button--split.kr-button--loading) .split-primary .content,
1140
+ :host(.kr-button--split.kr-button--success) .split-primary .content,
1141
+ :host(.kr-button--split.kr-button--error) .split-primary .content {
1142
+ visibility: hidden;
1143
+ }
1144
+
1145
+ :host(.kr-button--split.kr-button--loading) .split-trigger,
1146
+ :host(.kr-button--split.kr-button--success) .split-trigger,
1147
+ :host(.kr-button--split.kr-button--error) .split-trigger {
1148
+ pointer-events: none;
1149
+ opacity: 0.6;
1150
+ }
940
1151
  `;
941
1152
  __decorate$l([
942
1153
  n$1({ type: String, reflect: true })
@@ -962,6 +1173,9 @@
962
1173
  __decorate$l([
963
1174
  n$1({ type: String, reflect: true, attribute: 'icon-position' })
964
1175
  ], exports.KRButton.prototype, "iconPosition", void 0);
1176
+ __decorate$l([
1177
+ n$1({ type: Boolean, reflect: true })
1178
+ ], exports.KRButton.prototype, "split", void 0);
965
1179
  __decorate$l([
966
1180
  r$1()
967
1181
  ], exports.KRButton.prototype, "_state", void 0);