fantasia-ui 0.6.6 → 0.6.7

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.
@@ -5613,6 +5613,14 @@
5613
5613
  width: 100%;
5614
5614
  }
5615
5615
 
5616
+ .f-select-dropdown[data-placement=top] {
5617
+ transform-origin: bottom center;
5618
+ }
5619
+
5620
+ .f-select-dropdown[data-placement=bottom] {
5621
+ transform-origin: top center;
5622
+ }
5623
+
5616
5624
  .f-select {
5617
5625
  display: inline-flex;
5618
5626
  align-items: center;
@@ -5721,6 +5729,8 @@
5721
5729
  opacity: 0;
5722
5730
  pointer-events: none;
5723
5731
  transition: opacity 0.2s, color 0.2s;
5732
+ display: inline-flex;
5733
+ align-items: center;
5724
5734
  }
5725
5735
  .f-select__clear:hover {
5726
5736
  color: #64748b;
@@ -5740,6 +5750,19 @@
5740
5750
  .f-select.is-clearable:hover:not(.is-disabled) .f-select__arrow {
5741
5751
  opacity: 0;
5742
5752
  }
5753
+ .f-select.is-borderless {
5754
+ border-color: transparent;
5755
+ background: transparent;
5756
+ box-shadow: none;
5757
+ }
5758
+ .f-select.is-borderless:hover, .f-select.is-borderless.is-open {
5759
+ border-color: transparent;
5760
+ background: var(--bg-tertiary);
5761
+ box-shadow: none;
5762
+ }
5763
+ .f-select.is-borderless.is-disabled:hover {
5764
+ background: transparent;
5765
+ }
5743
5766
  .f-select__input {
5744
5767
  flex: 1;
5745
5768
  min-width: 0;
@@ -8419,12 +8442,18 @@ to {
8419
8442
  color: var(--text-muted);
8420
8443
  border: 1px solid var(--border2);
8421
8444
  }
8422
- .f-select-wrapper[data-v-2115ccc5] {
8445
+ .f-select-wrapper[data-v-42ec0325] {
8423
8446
  display: inline-block;
8424
8447
  position: relative;
8425
8448
  width: 100%;
8426
8449
  }
8427
- .f-select[data-v-2115ccc5] {
8450
+ .f-select-dropdown[data-placement=top][data-v-42ec0325] {
8451
+ transform-origin: bottom center;
8452
+ }
8453
+ .f-select-dropdown[data-placement=bottom][data-v-42ec0325] {
8454
+ transform-origin: top center;
8455
+ }
8456
+ .f-select[data-v-42ec0325] {
8428
8457
  display: inline-flex;
8429
8458
  align-items: center;
8430
8459
  justify-content: space-between;
@@ -8443,66 +8472,66 @@ to {
8443
8472
  transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
8444
8473
  /* ---------- 多选:标签 ---------- */
8445
8474
  }
8446
- .f-select[data-v-2115ccc5]:hover:not(.is-disabled) {
8475
+ .f-select[data-v-42ec0325]:hover:not(.is-disabled) {
8447
8476
  border-color: #ec4899;
8448
8477
  }
8449
- .f-select.is-open[data-v-2115ccc5]:not(.is-disabled), .f-select[data-v-2115ccc5]:focus-within:not(.is-disabled) {
8478
+ .f-select.is-open[data-v-42ec0325]:not(.is-disabled), .f-select[data-v-42ec0325]:focus-within:not(.is-disabled) {
8450
8479
  border-color: #ec4899;
8451
8480
  background: #fff;
8452
8481
  box-shadow: 0 0 0 2px rgba(236, 72, 153, 0.2274509804);
8453
8482
  }
8454
- .f-select.is-open:not(.is-disabled) .f-select__arrow[data-v-2115ccc5], .f-select:focus-within:not(.is-disabled) .f-select__arrow[data-v-2115ccc5] {
8483
+ .f-select.is-open:not(.is-disabled) .f-select__arrow[data-v-42ec0325], .f-select:focus-within:not(.is-disabled) .f-select__arrow[data-v-42ec0325] {
8455
8484
  transform: rotate(180deg);
8456
8485
  }
8457
- .f-select.is-active .f-select__label[data-v-2115ccc5] {
8486
+ .f-select.is-active .f-select__label[data-v-42ec0325] {
8458
8487
  color: #1e293b;
8459
8488
  }
8460
- .f-select.is-disabled[data-v-2115ccc5] {
8489
+ .f-select.is-disabled[data-v-42ec0325] {
8461
8490
  cursor: not-allowed;
8462
8491
  background-color: #f5f7fa;
8463
8492
  border-color: #e4e7ed;
8464
8493
  color: #c0c4cc;
8465
8494
  }
8466
- .f-select.is-disabled .f-select__label[data-v-2115ccc5],
8467
- .f-select.is-disabled .f-select__arrow[data-v-2115ccc5] {
8495
+ .f-select.is-disabled .f-select__label[data-v-42ec0325],
8496
+ .f-select.is-disabled .f-select__arrow[data-v-42ec0325] {
8468
8497
  cursor: not-allowed;
8469
8498
  }
8470
- .f-select.is-disabled .f-select__tag[data-v-2115ccc5] {
8499
+ .f-select.is-disabled .f-select__tag[data-v-42ec0325] {
8471
8500
  opacity: 0.6;
8472
8501
  }
8473
- .f-select--small[data-v-2115ccc5] {
8502
+ .f-select--small[data-v-42ec0325] {
8474
8503
  height: 32px;
8475
8504
  font-size: 13px;
8476
8505
  }
8477
- .f-select--small .f-select__label[data-v-2115ccc5] {
8506
+ .f-select--small .f-select__label[data-v-42ec0325] {
8478
8507
  font-size: 13px;
8479
8508
  }
8480
- .f-select--medium[data-v-2115ccc5] {
8509
+ .f-select--medium[data-v-42ec0325] {
8481
8510
  height: 36px;
8482
8511
  font-size: 14px;
8483
8512
  }
8484
- .f-select--large[data-v-2115ccc5] {
8513
+ .f-select--large[data-v-42ec0325] {
8485
8514
  height: 40px;
8486
8515
  font-size: 16px;
8487
8516
  }
8488
- .f-select--large .f-select__label[data-v-2115ccc5] {
8517
+ .f-select--large .f-select__label[data-v-42ec0325] {
8489
8518
  font-size: 16px;
8490
8519
  }
8491
- .f-select.is-multiple[data-v-2115ccc5] {
8520
+ .f-select.is-multiple[data-v-42ec0325] {
8492
8521
  height: auto;
8493
8522
  padding-top: 3px;
8494
8523
  padding-bottom: 3px;
8495
8524
  }
8496
- .f-select.is-multiple.f-select--small[data-v-2115ccc5] {
8525
+ .f-select.is-multiple.f-select--small[data-v-42ec0325] {
8497
8526
  min-height: 32px;
8498
8527
  }
8499
- .f-select.is-multiple.f-select--medium[data-v-2115ccc5] {
8528
+ .f-select.is-multiple.f-select--medium[data-v-42ec0325] {
8500
8529
  min-height: 36px;
8501
8530
  }
8502
- .f-select.is-multiple.f-select--large[data-v-2115ccc5] {
8531
+ .f-select.is-multiple.f-select--large[data-v-42ec0325] {
8503
8532
  min-height: 40px;
8504
8533
  }
8505
- .f-select__label[data-v-2115ccc5] {
8534
+ .f-select__label[data-v-42ec0325] {
8506
8535
  font-size: 14px;
8507
8536
  line-height: 1.5;
8508
8537
  color: #1e293b;
@@ -8512,46 +8541,61 @@ to {
8512
8541
  text-overflow: ellipsis;
8513
8542
  transition: color 0.2s;
8514
8543
  }
8515
- .f-select__label.is-placeholder[data-v-2115ccc5] {
8544
+ .f-select__label.is-placeholder[data-v-42ec0325] {
8516
8545
  color: #94a3b8;
8517
8546
  }
8518
- .f-select__suffix[data-v-2115ccc5] {
8547
+ .f-select__suffix[data-v-42ec0325] {
8519
8548
  display: grid;
8520
8549
  place-items: center;
8521
8550
  width: 14px;
8522
8551
  height: 14px;
8523
8552
  flex-shrink: 0;
8524
8553
  }
8525
- .f-select__suffix[data-v-2115ccc5] > * {
8554
+ .f-select__suffix[data-v-42ec0325] > * {
8526
8555
  grid-area: 1/1;
8527
8556
  }
8528
- .f-select__clear[data-v-2115ccc5] {
8557
+ .f-select__clear[data-v-42ec0325] {
8529
8558
  font-size: 14px;
8530
8559
  color: #94a3b8;
8531
8560
  cursor: pointer;
8532
8561
  opacity: 0;
8533
8562
  pointer-events: none;
8534
8563
  transition: opacity 0.2s, color 0.2s;
8564
+ display: inline-flex;
8565
+ align-items: center;
8535
8566
  }
8536
- .f-select__clear[data-v-2115ccc5]:hover {
8567
+ .f-select__clear[data-v-42ec0325]:hover {
8537
8568
  color: #64748b;
8538
8569
  }
8539
- .f-select__arrow[data-v-2115ccc5] {
8570
+ .f-select__arrow[data-v-42ec0325] {
8540
8571
  font-size: 14px;
8541
8572
  color: #94a3b8;
8542
8573
  transition: transform 0.3s, color 0.2s, opacity 0.2s;
8543
8574
  }
8544
- .f-select:hover:not(.is-disabled) .f-select__arrow[data-v-2115ccc5] {
8575
+ .f-select:hover:not(.is-disabled) .f-select__arrow[data-v-42ec0325] {
8545
8576
  color: #64748b;
8546
8577
  }
8547
- .f-select.is-clearable:hover:not(.is-disabled) .f-select__clear[data-v-2115ccc5] {
8578
+ .f-select.is-clearable:hover:not(.is-disabled) .f-select__clear[data-v-42ec0325] {
8548
8579
  opacity: 1;
8549
8580
  pointer-events: auto;
8550
8581
  }
8551
- .f-select.is-clearable:hover:not(.is-disabled) .f-select__arrow[data-v-2115ccc5] {
8582
+ .f-select.is-clearable:hover:not(.is-disabled) .f-select__arrow[data-v-42ec0325] {
8552
8583
  opacity: 0;
8553
8584
  }
8554
- .f-select__input[data-v-2115ccc5] {
8585
+ .f-select.is-borderless[data-v-42ec0325] {
8586
+ border-color: transparent;
8587
+ background: transparent;
8588
+ box-shadow: none;
8589
+ }
8590
+ .f-select.is-borderless[data-v-42ec0325]:hover, .f-select.is-borderless.is-open[data-v-42ec0325] {
8591
+ border-color: transparent;
8592
+ background: var(--bg-tertiary);
8593
+ box-shadow: none;
8594
+ }
8595
+ .f-select.is-borderless.is-disabled[data-v-42ec0325]:hover {
8596
+ background: transparent;
8597
+ }
8598
+ .f-select__input[data-v-42ec0325] {
8555
8599
  flex: 1;
8556
8600
  min-width: 0;
8557
8601
  padding: 0;
@@ -8562,16 +8606,16 @@ to {
8562
8606
  line-height: 1.5;
8563
8607
  color: #1e293b;
8564
8608
  }
8565
- .f-select__input[data-v-2115ccc5]::placeholder {
8609
+ .f-select__input[data-v-42ec0325]::placeholder {
8566
8610
  color: #94a3b8;
8567
8611
  }
8568
- .f-select__input.has-value[data-v-2115ccc5]::placeholder {
8612
+ .f-select__input.has-value[data-v-42ec0325]::placeholder {
8569
8613
  color: #64748b;
8570
8614
  }
8571
- .f-select__input.is-multiple[data-v-2115ccc5] {
8615
+ .f-select__input.is-multiple[data-v-42ec0325] {
8572
8616
  min-width: 60px;
8573
8617
  }
8574
- .f-select__tags[data-v-2115ccc5] {
8618
+ .f-select__tags[data-v-42ec0325] {
8575
8619
  flex: 1;
8576
8620
  min-width: 0;
8577
8621
  display: flex;
@@ -8579,35 +8623,35 @@ to {
8579
8623
  gap: 4px;
8580
8624
  align-items: center;
8581
8625
  }
8582
- .f-select__tag[data-v-2115ccc5] {
8626
+ .f-select__tag[data-v-42ec0325] {
8583
8627
  max-width: 200px;
8584
8628
  }
8585
- .f-select__tag[data-v-2115ccc5] .f-tag {
8629
+ .f-select__tag[data-v-42ec0325] .f-tag {
8586
8630
  max-width: 100%;
8587
8631
  }
8588
8632
  @media (hover: none) {
8589
- .f-select.is-clearable .f-select__clear[data-v-2115ccc5] {
8633
+ .f-select.is-clearable .f-select__clear[data-v-42ec0325] {
8590
8634
  opacity: 1;
8591
8635
  pointer-events: auto;
8592
8636
  }
8593
- .f-select.is-clearable .f-select__arrow[data-v-2115ccc5] {
8637
+ .f-select.is-clearable .f-select__arrow[data-v-42ec0325] {
8594
8638
  opacity: 0;
8595
8639
  }
8596
8640
  }
8597
8641
  /* ---------- 下拉面板 ---------- */
8598
- .f-select-dropdown[data-v-2115ccc5] {
8642
+ .f-select-dropdown[data-v-42ec0325] {
8599
8643
  position: fixed;
8600
8644
  background: #fff;
8601
8645
  border-radius: 4px;
8602
8646
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.12);
8603
8647
  z-index: 2000;
8604
8648
  }
8605
- .f-select-dropdown__content[data-v-2115ccc5] {
8649
+ .f-select-dropdown__content[data-v-42ec0325] {
8606
8650
  padding: 4px 0;
8607
8651
  }
8608
8652
 
8609
8653
  /* ---------- 选项 ---------- */
8610
- .f-select-option[data-v-2115ccc5] {
8654
+ .f-select-option[data-v-42ec0325] {
8611
8655
  padding: 8px 12px;
8612
8656
  font-size: 14px;
8613
8657
  line-height: 1.5;
@@ -8616,27 +8660,27 @@ to {
8616
8660
  transition: all 0.2s;
8617
8661
  user-select: none;
8618
8662
  }
8619
- .f-select-option[data-v-2115ccc5]:hover:not(.is-disabled) {
8663
+ .f-select-option[data-v-42ec0325]:hover:not(.is-disabled) {
8620
8664
  background-color: #f5f7fa;
8621
8665
  }
8622
- .f-select-option.is-selected[data-v-2115ccc5] {
8666
+ .f-select-option.is-selected[data-v-42ec0325] {
8623
8667
  color: #ec4899;
8624
8668
  font-weight: 500;
8625
8669
  background-color: #fdf2f8;
8626
8670
  }
8627
- .f-select-option.is-disabled[data-v-2115ccc5] {
8671
+ .f-select-option.is-disabled[data-v-42ec0325] {
8628
8672
  color: #c0c4cc;
8629
8673
  cursor: not-allowed;
8630
8674
  }
8631
- .f-select-option.is-empty[data-v-2115ccc5] {
8675
+ .f-select-option.is-empty[data-v-42ec0325] {
8632
8676
  text-align: center;
8633
8677
  color: #909399;
8634
8678
  cursor: default;
8635
8679
  }
8636
- .f-select-option.is-empty[data-v-2115ccc5]:hover {
8680
+ .f-select-option.is-empty[data-v-42ec0325]:hover {
8637
8681
  background-color: transparent;
8638
8682
  }
8639
- .f-select-option__label[data-v-2115ccc5] {
8683
+ .f-select-option__label[data-v-42ec0325] {
8640
8684
  display: block;
8641
8685
  white-space: nowrap;
8642
8686
  overflow: hidden;
@@ -8644,10 +8688,10 @@ to {
8644
8688
  }
8645
8689
 
8646
8690
  /* ---------- 新增选项按钮/表单 ---------- */
8647
- .f-select__add-section[data-v-2115ccc5] {
8691
+ .f-select__add-section[data-v-42ec0325] {
8648
8692
  border-top: 1px solid #e0e0e6;
8649
8693
  }
8650
- .f-select__add-option[data-v-2115ccc5] {
8694
+ .f-select__add-option[data-v-42ec0325] {
8651
8695
  display: flex;
8652
8696
  align-items: center;
8653
8697
  gap: 8px;
@@ -8657,17 +8701,17 @@ to {
8657
8701
  font-size: 14px;
8658
8702
  transition: all 0.2s ease;
8659
8703
  }
8660
- .f-select__add-option[data-v-2115ccc5]:hover {
8704
+ .f-select__add-option[data-v-42ec0325]:hover {
8661
8705
  background-color: #fdf2f8;
8662
8706
  }
8663
- .f-select__add-option[data-v-2115ccc5]:active {
8707
+ .f-select__add-option[data-v-42ec0325]:active {
8664
8708
  background-color: #fce7f3;
8665
8709
  }
8666
- .f-select__add-form[data-v-2115ccc5] {
8710
+ .f-select__add-form[data-v-42ec0325] {
8667
8711
  padding: 12px;
8668
8712
  background-color: #fafafa;
8669
8713
  }
8670
- .f-select__add-input[data-v-2115ccc5] {
8714
+ .f-select__add-input[data-v-42ec0325] {
8671
8715
  width: 100%;
8672
8716
  padding: 6px 10px;
8673
8717
  margin-bottom: 8px;
@@ -8677,22 +8721,22 @@ to {
8677
8721
  outline: none;
8678
8722
  transition: all 0.2s;
8679
8723
  }
8680
- .f-select__add-input[data-v-2115ccc5]::placeholder {
8724
+ .f-select__add-input[data-v-42ec0325]::placeholder {
8681
8725
  color: #94a3b8;
8682
8726
  }
8683
- .f-select__add-input[data-v-2115ccc5]:hover {
8727
+ .f-select__add-input[data-v-42ec0325]:hover {
8684
8728
  border-color: #ec4899;
8685
8729
  }
8686
- .f-select__add-input[data-v-2115ccc5]:focus {
8730
+ .f-select__add-input[data-v-42ec0325]:focus {
8687
8731
  border-color: #ec4899;
8688
8732
  box-shadow: 0 0 0 2px rgba(236, 72, 153, 0.2274509804);
8689
8733
  }
8690
- .f-select__add-actions[data-v-2115ccc5] {
8734
+ .f-select__add-actions[data-v-42ec0325] {
8691
8735
  display: flex;
8692
8736
  gap: 8px;
8693
8737
  justify-content: flex-end;
8694
8738
  }
8695
- .f-select__add-btn[data-v-2115ccc5] {
8739
+ .f-select__add-btn[data-v-42ec0325] {
8696
8740
  padding: 4px 12px;
8697
8741
  font-size: 13px;
8698
8742
  border: none;
@@ -8700,34 +8744,34 @@ to {
8700
8744
  cursor: pointer;
8701
8745
  transition: all 0.2s;
8702
8746
  }
8703
- .f-select__add-btn--confirm[data-v-2115ccc5] {
8747
+ .f-select__add-btn--confirm[data-v-42ec0325] {
8704
8748
  background-color: #ec4899;
8705
8749
  color: white;
8706
8750
  }
8707
- .f-select__add-btn--confirm[data-v-2115ccc5]:hover {
8751
+ .f-select__add-btn--confirm[data-v-42ec0325]:hover {
8708
8752
  background-color: #db2777;
8709
8753
  }
8710
- .f-select__add-btn--confirm[data-v-2115ccc5]:active {
8754
+ .f-select__add-btn--confirm[data-v-42ec0325]:active {
8711
8755
  background-color: #be185d;
8712
8756
  }
8713
- .f-select__add-btn--cancel[data-v-2115ccc5] {
8757
+ .f-select__add-btn--cancel[data-v-42ec0325] {
8714
8758
  background-color: #f1f5f9;
8715
8759
  color: #64748b;
8716
8760
  }
8717
- .f-select__add-btn--cancel[data-v-2115ccc5]:hover {
8761
+ .f-select__add-btn--cancel[data-v-42ec0325]:hover {
8718
8762
  background-color: #e2e8f0;
8719
8763
  }
8720
- .f-select__add-btn--cancel[data-v-2115ccc5]:active {
8764
+ .f-select__add-btn--cancel[data-v-42ec0325]:active {
8721
8765
  background-color: #cbd5e1;
8722
8766
  }
8723
8767
 
8724
8768
  /* ---------- 下拉动画 ---------- */
8725
- .f-select-dropdown-enter-active[data-v-2115ccc5],
8726
- .f-select-dropdown-leave-active[data-v-2115ccc5] {
8769
+ .f-select-dropdown-enter-active[data-v-42ec0325],
8770
+ .f-select-dropdown-leave-active[data-v-42ec0325] {
8727
8771
  transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
8728
8772
  }
8729
- .f-select-dropdown-enter-from[data-v-2115ccc5],
8730
- .f-select-dropdown-leave-to[data-v-2115ccc5] {
8773
+ .f-select-dropdown-enter-from[data-v-42ec0325],
8774
+ .f-select-dropdown-leave-to[data-v-42ec0325] {
8731
8775
  opacity: 0;
8732
8776
  transform: scaleY(0.9);
8733
8777
  }.f-date-picker[data-v-82ea76e0] {
@@ -1061,24 +1061,36 @@ const _hoisted_3$u = {
1061
1061
  };
1062
1062
  const _hoisted_4$j = ["placeholder"];
1063
1063
  const _hoisted_5$g = { class: "f-select__suffix" };
1064
- const _hoisted_6$e = { class: "f-select-dropdown__content" };
1065
- const _hoisted_7$9 = ["onClick"];
1066
- const _hoisted_8$8 = { class: "f-select-option__label" };
1067
- const _hoisted_9$7 = {
1064
+ const _hoisted_6$e = ["data-placement"];
1065
+ const _hoisted_7$9 = { class: "f-select-dropdown__content" };
1066
+ const _hoisted_8$8 = ["onClick"];
1067
+ const _hoisted_9$7 = { class: "f-select-option__label" };
1068
+ const _hoisted_10$6 = {
1068
1069
  key: 0,
1069
1070
  class: "f-select-option is-empty"
1070
1071
  };
1071
- const _hoisted_10$6 = {
1072
+ const _hoisted_11$5 = {
1072
1073
  key: 0,
1073
1074
  class: "f-select__add-section"
1074
1075
  };
1075
- const _hoisted_11$5 = {
1076
+ const _hoisted_12$3 = {
1076
1077
  key: 0,
1077
1078
  class: "f-select__add-form"
1078
1079
  };
1080
+ const OPTION_HEIGHT = 36;
1081
+ const ADD_SECTION_HEIGHT = 44;
1082
+ const PANEL_PADDING = 8;
1083
+ const GAP$2 = 4;
1084
+ const VIEWPORT_MARGIN = 8;
1079
1085
  const _sfc_main$O = /* @__PURE__ */ defineComponent({
1080
1086
  __name: "FSelect",
1081
1087
  props: /* @__PURE__ */ mergeModels({
1088
+ bordered: { type: Boolean, default: true },
1089
+ placement: { default: "auto" },
1090
+ dropdownClass: {},
1091
+ optionClass: {},
1092
+ minDropdownWidth: { default: 0 },
1093
+ maxDropdownHeight: { default: 240 },
1082
1094
  options: {},
1083
1095
  placeholder: { default: "请选择" },
1084
1096
  disabled: { type: Boolean, default: false },
@@ -1117,44 +1129,63 @@ const _sfc_main$O = /* @__PURE__ */ defineComponent({
1117
1129
  return props.options.filter((o) => String(o.label).toLowerCase().includes(kw));
1118
1130
  });
1119
1131
  const dropdownStyle = ref({});
1132
+ const dropdownMaxHeight = ref(props.maxDropdownHeight);
1133
+ const currentPlacement = ref("bottom");
1134
+ const estimatedHeight = computed(() => {
1135
+ const rows = Math.max(filteredOptions.value.length, 1);
1136
+ return rows * OPTION_HEIGHT + PANEL_PADDING + (props.showAddOption ? ADD_SECTION_HEIGHT : 0);
1137
+ });
1120
1138
  const updateDropdownPosition = () => {
1121
- if (!selectRef.value) return;
1139
+ if (!isOpen.value || !selectRef.value) return;
1122
1140
  const rect = selectRef.value.getBoundingClientRect();
1123
- const viewportHeight = window.innerHeight;
1124
- const spaceBelow = viewportHeight - rect.bottom;
1125
- const spaceAbove = rect.top;
1126
- let top = rect.bottom + 4;
1127
- let maxHeight = "240px";
1128
- if (spaceBelow < 240 && spaceAbove > spaceBelow) {
1129
- top = rect.top - 4;
1130
- maxHeight = `${Math.min(spaceAbove - 8, 240)}px`;
1131
- } else {
1132
- maxHeight = `${Math.min(spaceBelow - 8, 240)}px`;
1133
- }
1134
- dropdownStyle.value = {
1141
+ const vh = window.innerHeight;
1142
+ const vw = window.innerWidth;
1143
+ const spaceBelow = vh - rect.bottom - GAP$2 - VIEWPORT_MARGIN;
1144
+ const spaceAbove = rect.top - GAP$2 - VIEWPORT_MARGIN;
1145
+ const desired = Math.min(estimatedHeight.value, props.maxDropdownHeight);
1146
+ let placeTop;
1147
+ if (props.placement === "top") placeTop = true;
1148
+ else if (props.placement === "bottom") placeTop = false;
1149
+ else placeTop = spaceBelow < desired && spaceAbove > spaceBelow;
1150
+ currentPlacement.value = placeTop ? "top" : "bottom";
1151
+ const space = placeTop ? spaceAbove : spaceBelow;
1152
+ dropdownMaxHeight.value = Math.max(Math.min(props.maxDropdownHeight, space), 80);
1153
+ const width = Math.max(rect.width, props.minDropdownWidth);
1154
+ const left = Math.max(VIEWPORT_MARGIN, Math.min(rect.left, vw - width - VIEWPORT_MARGIN));
1155
+ const style = {
1135
1156
  position: "fixed",
1136
- top: `${top}px`,
1137
- left: `${rect.left}px`,
1138
- width: `${rect.width}px`,
1139
- maxHeight,
1157
+ left: `${left}px`,
1158
+ width: `${width}px`,
1140
1159
  zIndex: "2000"
1141
1160
  };
1161
+ if (placeTop) {
1162
+ style.bottom = `${vh - rect.top + GAP$2}px`;
1163
+ } else {
1164
+ style.top = `${rect.bottom + GAP$2}px`;
1165
+ }
1166
+ dropdownStyle.value = style;
1142
1167
  };
1143
1168
  watch(isOpen, (open) => {
1144
1169
  if (open) {
1170
+ updateDropdownPosition();
1145
1171
  if (props.filterable) nextTick(() => {
1146
1172
  var _a;
1147
1173
  return (_a = inputRef.value) == null ? void 0 : _a.focus();
1148
1174
  });
1149
- updateDropdownPosition();
1150
1175
  } else {
1151
1176
  keyword.value = "";
1177
+ isAdding.value = false;
1152
1178
  }
1153
1179
  });
1180
+ watch(filteredOptions, () => {
1181
+ if (isOpen.value) nextTick(updateDropdownPosition);
1182
+ });
1183
+ const selectedOption = computed(
1184
+ () => props.options.find((o) => o.key === modelValue.value)
1185
+ );
1154
1186
  const selectedLabel = computed(() => {
1155
- var _a;
1156
- const option = props.options.find((o) => o.key === modelValue.value);
1157
- return (_a = option == null ? void 0 : option.label) != null ? _a : props.placeholder;
1187
+ var _a, _b;
1188
+ return (_b = (_a = selectedOption.value) == null ? void 0 : _a.label) != null ? _b : props.placeholder;
1158
1189
  });
1159
1190
  const handleOptionClick = (option) => {
1160
1191
  if (option.disabled) return;
@@ -1178,7 +1209,12 @@ const _sfc_main$O = /* @__PURE__ */ defineComponent({
1178
1209
  }
1179
1210
  };
1180
1211
  const isSelected = (key) => {
1181
- return props.multiple && multiValue.value.includes(key);
1212
+ return props.multiple ? multiValue.value.includes(key) : modelValue.value === key;
1213
+ };
1214
+ const getOptionClass = (opt) => {
1215
+ const c = props.optionClass;
1216
+ if (!c) return "";
1217
+ return typeof c === "function" ? c(opt, isSelected(opt.key)) : c;
1182
1218
  };
1183
1219
  const stopWhenOpen = (e) => {
1184
1220
  if (isOpen.value) e.stopPropagation();
@@ -1201,12 +1237,6 @@ const _sfc_main$O = /* @__PURE__ */ defineComponent({
1201
1237
  const handleInputClick = () => {
1202
1238
  if (!props.disabled) isOpen.value = true;
1203
1239
  };
1204
- const handleClear = (e) => {
1205
- e.stopPropagation();
1206
- modelValue.value = props.multiple ? [] : void 0;
1207
- keyword.value = "";
1208
- emit("clear");
1209
- };
1210
1240
  const isAdding = ref(false);
1211
1241
  const newOptionLabel = ref("");
1212
1242
  const newOptionKey = ref("");
@@ -1214,6 +1244,7 @@ const _sfc_main$O = /* @__PURE__ */ defineComponent({
1214
1244
  isAdding.value = true;
1215
1245
  newOptionLabel.value = "";
1216
1246
  newOptionKey.value = "";
1247
+ nextTick(updateDropdownPosition);
1217
1248
  };
1218
1249
  const cancelAdd = () => {
1219
1250
  isAdding.value = false;
@@ -1240,11 +1271,23 @@ const _sfc_main$O = /* @__PURE__ */ defineComponent({
1240
1271
  newOptionLabel.value = "";
1241
1272
  newOptionKey.value = "";
1242
1273
  };
1274
+ const handleTriggerClick = (e) => {
1275
+ if (props.disabled) return;
1276
+ const target = e.target;
1277
+ if (target == null ? void 0 : target.closest(".f-select__clear, .f-select__tag")) return;
1278
+ isOpen.value = !isOpen.value;
1279
+ };
1280
+ const handleClear = () => {
1281
+ const empty = props.multiple ? [] : null;
1282
+ modelValue.value = empty;
1283
+ keyword.value = "";
1284
+ emit("change", empty, props.multiple ? [] : {});
1285
+ emit("clear");
1286
+ };
1243
1287
  const handleWindowClick = (e) => {
1244
- var _a, _b;
1245
1288
  if (!isOpen.value) return;
1246
- const target = e.target;
1247
- if (((_a = selectRef.value) == null ? void 0 : _a.contains(target)) || ((_b = dropdownRef.value) == null ? void 0 : _b.contains(target))) {
1289
+ const path = e.composedPath();
1290
+ if (selectRef.value && path.includes(selectRef.value) || dropdownRef.value && path.includes(dropdownRef.value)) {
1248
1291
  return;
1249
1292
  }
1250
1293
  isOpen.value = false;
@@ -1265,9 +1308,10 @@ const _sfc_main$O = /* @__PURE__ */ defineComponent({
1265
1308
  "is-disabled": _ctx.disabled,
1266
1309
  "is-clearable": unref(showClear),
1267
1310
  "is-multiple": _ctx.multiple,
1311
+ "is-borderless": !_ctx.bordered,
1268
1312
  [`f-select--${_ctx.size}`]: _ctx.size
1269
1313
  }]),
1270
- onClick: _cache[4] || (_cache[4] = ($event) => !_ctx.disabled && (isOpen.value = !unref(isOpen)))
1314
+ onClick: handleTriggerClick
1271
1315
  }, [
1272
1316
  _ctx.multiple ? (openBlock(), createElementBlock("div", _hoisted_1$C, [
1273
1317
  (openBlock(true), createElementBlock(Fragment, null, renderList(unref(selectedOptions), (opt) => {
@@ -1316,13 +1360,20 @@ const _sfc_main$O = /* @__PURE__ */ defineComponent({
1316
1360
  ]) : (openBlock(), createElementBlock("span", {
1317
1361
  key: 1,
1318
1362
  class: normalizeClass(["f-select__label", { "is-placeholder": !unref(hasValue) }])
1319
- }, toDisplayString(unref(selectedLabel)), 3))
1363
+ }, [
1364
+ renderSlot(_ctx.$slots, "label", {
1365
+ option: unref(selectedOption),
1366
+ label: unref(selectedLabel)
1367
+ }, () => [
1368
+ createTextVNode(toDisplayString(unref(selectedLabel)), 1)
1369
+ ], true)
1370
+ ], 2))
1320
1371
  ], 64)),
1321
1372
  createElementVNode("div", _hoisted_5$g, [
1322
1373
  unref(showClear) ? (openBlock(), createBlock(FIcon, {
1323
1374
  key: 0,
1324
1375
  class: "f-select__clear",
1325
- onClick: withModifiers(handleClear, ["stop"])
1376
+ onClick: handleClear
1326
1377
  }, {
1327
1378
  default: withCtx(() => [
1328
1379
  createVNode(unref(CloseCircleOutline))
@@ -1344,37 +1395,51 @@ const _sfc_main$O = /* @__PURE__ */ defineComponent({
1344
1395
  key: 0,
1345
1396
  ref_key: "dropdownRef",
1346
1397
  ref: dropdownRef,
1347
- class: "f-select-dropdown",
1398
+ class: normalizeClass(["f-select-dropdown", _ctx.dropdownClass]),
1399
+ "data-placement": unref(currentPlacement),
1348
1400
  style: normalizeStyle(unref(dropdownStyle)),
1349
- onClick: _cache[9] || (_cache[9] = withModifiers(() => {
1401
+ onClick: _cache[8] || (_cache[8] = withModifiers(() => {
1350
1402
  }, ["stop"]))
1351
1403
  }, [
1352
1404
  createVNode(FScrollbar, {
1353
- "max-height": unref(dropdownStyle).maxHeight
1405
+ "max-height": `${unref(dropdownMaxHeight)}px`
1354
1406
  }, {
1355
1407
  default: withCtx(() => [
1356
- createElementVNode("div", _hoisted_6$e, [
1408
+ createElementVNode("div", _hoisted_7$9, [
1357
1409
  (openBlock(true), createElementBlock(Fragment, null, renderList(unref(filteredOptions), (opt) => {
1358
1410
  return openBlock(), createElementBlock("div", {
1359
1411
  key: opt.key,
1360
- class: normalizeClass(["f-select-option", {
1361
- "is-disabled": opt.disabled,
1362
- "is-selected": isSelected(opt.key)
1363
- }]),
1412
+ class: normalizeClass(["f-select-option", [
1413
+ getOptionClass(opt),
1414
+ {
1415
+ "is-disabled": opt.disabled,
1416
+ "is-selected": isSelected(opt.key)
1417
+ }
1418
+ ]]),
1364
1419
  onClick: ($event) => handleOptionClick(opt)
1365
1420
  }, [
1366
- createElementVNode("span", _hoisted_8$8, toDisplayString(opt.label), 1)
1367
- ], 10, _hoisted_7$9);
1421
+ renderSlot(_ctx.$slots, "option", {
1422
+ option: opt,
1423
+ selected: isSelected(opt.key)
1424
+ }, () => [
1425
+ createElementVNode("span", _hoisted_9$7, toDisplayString(opt.label), 1)
1426
+ ], true)
1427
+ ], 10, _hoisted_8$8);
1368
1428
  }), 128)),
1369
- unref(filteredOptions).length === 0 ? (openBlock(), createElementBlock("div", _hoisted_9$7, " 暂无数据 ")) : createCommentVNode("", true)
1429
+ unref(filteredOptions).length === 0 ? (openBlock(), createElementBlock("div", _hoisted_10$6, [
1430
+ renderSlot(_ctx.$slots, "empty", {}, () => [
1431
+ _cache[9] || (_cache[9] = createTextVNode("暂无数据"))
1432
+ ], true)
1433
+ ])) : createCommentVNode("", true)
1370
1434
  ]),
1371
- _ctx.showAddOption ? (openBlock(), createElementBlock("div", _hoisted_10$6, [
1372
- unref(isAdding) ? (openBlock(), createElementBlock("div", _hoisted_11$5, [
1435
+ renderSlot(_ctx.$slots, "footer", {}, void 0, true),
1436
+ _ctx.showAddOption ? (openBlock(), createElementBlock("div", _hoisted_11$5, [
1437
+ unref(isAdding) ? (openBlock(), createElementBlock("div", _hoisted_12$3, [
1373
1438
  withDirectives(createElementVNode("input", {
1374
- "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => isRef(newOptionLabel) ? newOptionLabel.value = $event : null),
1439
+ "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => isRef(newOptionLabel) ? newOptionLabel.value = $event : null),
1375
1440
  class: "f-select__add-input",
1376
1441
  placeholder: "选项名称(必填)",
1377
- onClick: _cache[6] || (_cache[6] = withModifiers(() => {
1442
+ onClick: _cache[5] || (_cache[5] = withModifiers(() => {
1378
1443
  }, ["stop"])),
1379
1444
  onKeydown: [
1380
1445
  withKeys(confirmAdd, ["enter"]),
@@ -1384,10 +1449,10 @@ const _sfc_main$O = /* @__PURE__ */ defineComponent({
1384
1449
  [vModelText, unref(newOptionLabel)]
1385
1450
  ]),
1386
1451
  withDirectives(createElementVNode("input", {
1387
- "onUpdate:modelValue": _cache[7] || (_cache[7] = ($event) => isRef(newOptionKey) ? newOptionKey.value = $event : null),
1452
+ "onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => isRef(newOptionKey) ? newOptionKey.value = $event : null),
1388
1453
  class: "f-select__add-input",
1389
1454
  placeholder: "选项值(可选)",
1390
- onClick: _cache[8] || (_cache[8] = withModifiers(() => {
1455
+ onClick: _cache[7] || (_cache[7] = withModifiers(() => {
1391
1456
  }, ["stop"])),
1392
1457
  onKeydown: [
1393
1458
  withKeys(confirmAdd, ["enter"]),
@@ -1415,18 +1480,18 @@ const _sfc_main$O = /* @__PURE__ */ defineComponent({
1415
1480
  }, toDisplayString(_ctx.addOptionText), 1))
1416
1481
  ])) : createCommentVNode("", true)
1417
1482
  ]),
1418
- _: 1
1483
+ _: 3
1419
1484
  }, 8, ["max-height"])
1420
- ], 4)) : createCommentVNode("", true)
1485
+ ], 14, _hoisted_6$e)) : createCommentVNode("", true)
1421
1486
  ]),
1422
- _: 1
1487
+ _: 3
1423
1488
  })
1424
1489
  ]))
1425
1490
  ], 512);
1426
1491
  };
1427
1492
  }
1428
1493
  });
1429
- const FSelect = /* @__PURE__ */ _export_sfc(_sfc_main$O, [["__scopeId", "data-v-2115ccc5"]]);
1494
+ const FSelect = /* @__PURE__ */ _export_sfc(_sfc_main$O, [["__scopeId", "data-v-42ec0325"]]);
1430
1495
  const _hoisted_1$B = { class: "f-date-picker__inner" };
1431
1496
  const _hoisted_2$w = ["value", "placeholder", "disabled"];
1432
1497
  const _hoisted_3$t = { class: "f-date-picker-panel" };
@@ -1062,24 +1062,36 @@ var __async = (__this, __arguments, generator) => {
1062
1062
  };
1063
1063
  const _hoisted_4$j = ["placeholder"];
1064
1064
  const _hoisted_5$g = { class: "f-select__suffix" };
1065
- const _hoisted_6$e = { class: "f-select-dropdown__content" };
1066
- const _hoisted_7$9 = ["onClick"];
1067
- const _hoisted_8$8 = { class: "f-select-option__label" };
1068
- const _hoisted_9$7 = {
1065
+ const _hoisted_6$e = ["data-placement"];
1066
+ const _hoisted_7$9 = { class: "f-select-dropdown__content" };
1067
+ const _hoisted_8$8 = ["onClick"];
1068
+ const _hoisted_9$7 = { class: "f-select-option__label" };
1069
+ const _hoisted_10$6 = {
1069
1070
  key: 0,
1070
1071
  class: "f-select-option is-empty"
1071
1072
  };
1072
- const _hoisted_10$6 = {
1073
+ const _hoisted_11$5 = {
1073
1074
  key: 0,
1074
1075
  class: "f-select__add-section"
1075
1076
  };
1076
- const _hoisted_11$5 = {
1077
+ const _hoisted_12$3 = {
1077
1078
  key: 0,
1078
1079
  class: "f-select__add-form"
1079
1080
  };
1081
+ const OPTION_HEIGHT = 36;
1082
+ const ADD_SECTION_HEIGHT = 44;
1083
+ const PANEL_PADDING = 8;
1084
+ const GAP$2 = 4;
1085
+ const VIEWPORT_MARGIN = 8;
1080
1086
  const _sfc_main$O = /* @__PURE__ */ vue.defineComponent({
1081
1087
  __name: "FSelect",
1082
1088
  props: /* @__PURE__ */ vue.mergeModels({
1089
+ bordered: { type: Boolean, default: true },
1090
+ placement: { default: "auto" },
1091
+ dropdownClass: {},
1092
+ optionClass: {},
1093
+ minDropdownWidth: { default: 0 },
1094
+ maxDropdownHeight: { default: 240 },
1083
1095
  options: {},
1084
1096
  placeholder: { default: "请选择" },
1085
1097
  disabled: { type: Boolean, default: false },
@@ -1118,44 +1130,63 @@ var __async = (__this, __arguments, generator) => {
1118
1130
  return props.options.filter((o) => String(o.label).toLowerCase().includes(kw));
1119
1131
  });
1120
1132
  const dropdownStyle = vue.ref({});
1133
+ const dropdownMaxHeight = vue.ref(props.maxDropdownHeight);
1134
+ const currentPlacement = vue.ref("bottom");
1135
+ const estimatedHeight = vue.computed(() => {
1136
+ const rows = Math.max(filteredOptions.value.length, 1);
1137
+ return rows * OPTION_HEIGHT + PANEL_PADDING + (props.showAddOption ? ADD_SECTION_HEIGHT : 0);
1138
+ });
1121
1139
  const updateDropdownPosition = () => {
1122
- if (!selectRef.value) return;
1140
+ if (!isOpen.value || !selectRef.value) return;
1123
1141
  const rect = selectRef.value.getBoundingClientRect();
1124
- const viewportHeight = window.innerHeight;
1125
- const spaceBelow = viewportHeight - rect.bottom;
1126
- const spaceAbove = rect.top;
1127
- let top = rect.bottom + 4;
1128
- let maxHeight = "240px";
1129
- if (spaceBelow < 240 && spaceAbove > spaceBelow) {
1130
- top = rect.top - 4;
1131
- maxHeight = `${Math.min(spaceAbove - 8, 240)}px`;
1132
- } else {
1133
- maxHeight = `${Math.min(spaceBelow - 8, 240)}px`;
1134
- }
1135
- dropdownStyle.value = {
1142
+ const vh = window.innerHeight;
1143
+ const vw = window.innerWidth;
1144
+ const spaceBelow = vh - rect.bottom - GAP$2 - VIEWPORT_MARGIN;
1145
+ const spaceAbove = rect.top - GAP$2 - VIEWPORT_MARGIN;
1146
+ const desired = Math.min(estimatedHeight.value, props.maxDropdownHeight);
1147
+ let placeTop;
1148
+ if (props.placement === "top") placeTop = true;
1149
+ else if (props.placement === "bottom") placeTop = false;
1150
+ else placeTop = spaceBelow < desired && spaceAbove > spaceBelow;
1151
+ currentPlacement.value = placeTop ? "top" : "bottom";
1152
+ const space = placeTop ? spaceAbove : spaceBelow;
1153
+ dropdownMaxHeight.value = Math.max(Math.min(props.maxDropdownHeight, space), 80);
1154
+ const width = Math.max(rect.width, props.minDropdownWidth);
1155
+ const left = Math.max(VIEWPORT_MARGIN, Math.min(rect.left, vw - width - VIEWPORT_MARGIN));
1156
+ const style = {
1136
1157
  position: "fixed",
1137
- top: `${top}px`,
1138
- left: `${rect.left}px`,
1139
- width: `${rect.width}px`,
1140
- maxHeight,
1158
+ left: `${left}px`,
1159
+ width: `${width}px`,
1141
1160
  zIndex: "2000"
1142
1161
  };
1162
+ if (placeTop) {
1163
+ style.bottom = `${vh - rect.top + GAP$2}px`;
1164
+ } else {
1165
+ style.top = `${rect.bottom + GAP$2}px`;
1166
+ }
1167
+ dropdownStyle.value = style;
1143
1168
  };
1144
1169
  vue.watch(isOpen, (open) => {
1145
1170
  if (open) {
1171
+ updateDropdownPosition();
1146
1172
  if (props.filterable) vue.nextTick(() => {
1147
1173
  var _a;
1148
1174
  return (_a = inputRef.value) == null ? void 0 : _a.focus();
1149
1175
  });
1150
- updateDropdownPosition();
1151
1176
  } else {
1152
1177
  keyword.value = "";
1178
+ isAdding.value = false;
1153
1179
  }
1154
1180
  });
1181
+ vue.watch(filteredOptions, () => {
1182
+ if (isOpen.value) vue.nextTick(updateDropdownPosition);
1183
+ });
1184
+ const selectedOption = vue.computed(
1185
+ () => props.options.find((o) => o.key === modelValue.value)
1186
+ );
1155
1187
  const selectedLabel = vue.computed(() => {
1156
- var _a;
1157
- const option = props.options.find((o) => o.key === modelValue.value);
1158
- return (_a = option == null ? void 0 : option.label) != null ? _a : props.placeholder;
1188
+ var _a, _b;
1189
+ return (_b = (_a = selectedOption.value) == null ? void 0 : _a.label) != null ? _b : props.placeholder;
1159
1190
  });
1160
1191
  const handleOptionClick = (option) => {
1161
1192
  if (option.disabled) return;
@@ -1179,7 +1210,12 @@ var __async = (__this, __arguments, generator) => {
1179
1210
  }
1180
1211
  };
1181
1212
  const isSelected = (key) => {
1182
- return props.multiple && multiValue.value.includes(key);
1213
+ return props.multiple ? multiValue.value.includes(key) : modelValue.value === key;
1214
+ };
1215
+ const getOptionClass = (opt) => {
1216
+ const c = props.optionClass;
1217
+ if (!c) return "";
1218
+ return typeof c === "function" ? c(opt, isSelected(opt.key)) : c;
1183
1219
  };
1184
1220
  const stopWhenOpen = (e) => {
1185
1221
  if (isOpen.value) e.stopPropagation();
@@ -1202,12 +1238,6 @@ var __async = (__this, __arguments, generator) => {
1202
1238
  const handleInputClick = () => {
1203
1239
  if (!props.disabled) isOpen.value = true;
1204
1240
  };
1205
- const handleClear = (e) => {
1206
- e.stopPropagation();
1207
- modelValue.value = props.multiple ? [] : void 0;
1208
- keyword.value = "";
1209
- emit("clear");
1210
- };
1211
1241
  const isAdding = vue.ref(false);
1212
1242
  const newOptionLabel = vue.ref("");
1213
1243
  const newOptionKey = vue.ref("");
@@ -1215,6 +1245,7 @@ var __async = (__this, __arguments, generator) => {
1215
1245
  isAdding.value = true;
1216
1246
  newOptionLabel.value = "";
1217
1247
  newOptionKey.value = "";
1248
+ vue.nextTick(updateDropdownPosition);
1218
1249
  };
1219
1250
  const cancelAdd = () => {
1220
1251
  isAdding.value = false;
@@ -1241,11 +1272,23 @@ var __async = (__this, __arguments, generator) => {
1241
1272
  newOptionLabel.value = "";
1242
1273
  newOptionKey.value = "";
1243
1274
  };
1275
+ const handleTriggerClick = (e) => {
1276
+ if (props.disabled) return;
1277
+ const target = e.target;
1278
+ if (target == null ? void 0 : target.closest(".f-select__clear, .f-select__tag")) return;
1279
+ isOpen.value = !isOpen.value;
1280
+ };
1281
+ const handleClear = () => {
1282
+ const empty = props.multiple ? [] : null;
1283
+ modelValue.value = empty;
1284
+ keyword.value = "";
1285
+ emit("change", empty, props.multiple ? [] : {});
1286
+ emit("clear");
1287
+ };
1244
1288
  const handleWindowClick = (e) => {
1245
- var _a, _b;
1246
1289
  if (!isOpen.value) return;
1247
- const target = e.target;
1248
- if (((_a = selectRef.value) == null ? void 0 : _a.contains(target)) || ((_b = dropdownRef.value) == null ? void 0 : _b.contains(target))) {
1290
+ const path = e.composedPath();
1291
+ if (selectRef.value && path.includes(selectRef.value) || dropdownRef.value && path.includes(dropdownRef.value)) {
1249
1292
  return;
1250
1293
  }
1251
1294
  isOpen.value = false;
@@ -1266,9 +1309,10 @@ var __async = (__this, __arguments, generator) => {
1266
1309
  "is-disabled": _ctx.disabled,
1267
1310
  "is-clearable": vue.unref(showClear),
1268
1311
  "is-multiple": _ctx.multiple,
1312
+ "is-borderless": !_ctx.bordered,
1269
1313
  [`f-select--${_ctx.size}`]: _ctx.size
1270
1314
  }]),
1271
- onClick: _cache[4] || (_cache[4] = ($event) => !_ctx.disabled && (isOpen.value = !vue.unref(isOpen)))
1315
+ onClick: handleTriggerClick
1272
1316
  }, [
1273
1317
  _ctx.multiple ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$C, [
1274
1318
  (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(vue.unref(selectedOptions), (opt) => {
@@ -1317,13 +1361,20 @@ var __async = (__this, __arguments, generator) => {
1317
1361
  ]) : (vue.openBlock(), vue.createElementBlock("span", {
1318
1362
  key: 1,
1319
1363
  class: vue.normalizeClass(["f-select__label", { "is-placeholder": !vue.unref(hasValue) }])
1320
- }, vue.toDisplayString(vue.unref(selectedLabel)), 3))
1364
+ }, [
1365
+ vue.renderSlot(_ctx.$slots, "label", {
1366
+ option: vue.unref(selectedOption),
1367
+ label: vue.unref(selectedLabel)
1368
+ }, () => [
1369
+ vue.createTextVNode(vue.toDisplayString(vue.unref(selectedLabel)), 1)
1370
+ ], true)
1371
+ ], 2))
1321
1372
  ], 64)),
1322
1373
  vue.createElementVNode("div", _hoisted_5$g, [
1323
1374
  vue.unref(showClear) ? (vue.openBlock(), vue.createBlock(FIcon, {
1324
1375
  key: 0,
1325
1376
  class: "f-select__clear",
1326
- onClick: vue.withModifiers(handleClear, ["stop"])
1377
+ onClick: handleClear
1327
1378
  }, {
1328
1379
  default: vue.withCtx(() => [
1329
1380
  vue.createVNode(vue.unref(ionicons5.CloseCircleOutline))
@@ -1345,37 +1396,51 @@ var __async = (__this, __arguments, generator) => {
1345
1396
  key: 0,
1346
1397
  ref_key: "dropdownRef",
1347
1398
  ref: dropdownRef,
1348
- class: "f-select-dropdown",
1399
+ class: vue.normalizeClass(["f-select-dropdown", _ctx.dropdownClass]),
1400
+ "data-placement": vue.unref(currentPlacement),
1349
1401
  style: vue.normalizeStyle(vue.unref(dropdownStyle)),
1350
- onClick: _cache[9] || (_cache[9] = vue.withModifiers(() => {
1402
+ onClick: _cache[8] || (_cache[8] = vue.withModifiers(() => {
1351
1403
  }, ["stop"]))
1352
1404
  }, [
1353
1405
  vue.createVNode(FScrollbar, {
1354
- "max-height": vue.unref(dropdownStyle).maxHeight
1406
+ "max-height": `${vue.unref(dropdownMaxHeight)}px`
1355
1407
  }, {
1356
1408
  default: vue.withCtx(() => [
1357
- vue.createElementVNode("div", _hoisted_6$e, [
1409
+ vue.createElementVNode("div", _hoisted_7$9, [
1358
1410
  (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(vue.unref(filteredOptions), (opt) => {
1359
1411
  return vue.openBlock(), vue.createElementBlock("div", {
1360
1412
  key: opt.key,
1361
- class: vue.normalizeClass(["f-select-option", {
1362
- "is-disabled": opt.disabled,
1363
- "is-selected": isSelected(opt.key)
1364
- }]),
1413
+ class: vue.normalizeClass(["f-select-option", [
1414
+ getOptionClass(opt),
1415
+ {
1416
+ "is-disabled": opt.disabled,
1417
+ "is-selected": isSelected(opt.key)
1418
+ }
1419
+ ]]),
1365
1420
  onClick: ($event) => handleOptionClick(opt)
1366
1421
  }, [
1367
- vue.createElementVNode("span", _hoisted_8$8, vue.toDisplayString(opt.label), 1)
1368
- ], 10, _hoisted_7$9);
1422
+ vue.renderSlot(_ctx.$slots, "option", {
1423
+ option: opt,
1424
+ selected: isSelected(opt.key)
1425
+ }, () => [
1426
+ vue.createElementVNode("span", _hoisted_9$7, vue.toDisplayString(opt.label), 1)
1427
+ ], true)
1428
+ ], 10, _hoisted_8$8);
1369
1429
  }), 128)),
1370
- vue.unref(filteredOptions).length === 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_9$7, " 暂无数据 ")) : vue.createCommentVNode("", true)
1430
+ vue.unref(filteredOptions).length === 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_10$6, [
1431
+ vue.renderSlot(_ctx.$slots, "empty", {}, () => [
1432
+ _cache[9] || (_cache[9] = vue.createTextVNode("暂无数据"))
1433
+ ], true)
1434
+ ])) : vue.createCommentVNode("", true)
1371
1435
  ]),
1372
- _ctx.showAddOption ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_10$6, [
1373
- vue.unref(isAdding) ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_11$5, [
1436
+ vue.renderSlot(_ctx.$slots, "footer", {}, void 0, true),
1437
+ _ctx.showAddOption ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_11$5, [
1438
+ vue.unref(isAdding) ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_12$3, [
1374
1439
  vue.withDirectives(vue.createElementVNode("input", {
1375
- "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => vue.isRef(newOptionLabel) ? newOptionLabel.value = $event : null),
1440
+ "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => vue.isRef(newOptionLabel) ? newOptionLabel.value = $event : null),
1376
1441
  class: "f-select__add-input",
1377
1442
  placeholder: "选项名称(必填)",
1378
- onClick: _cache[6] || (_cache[6] = vue.withModifiers(() => {
1443
+ onClick: _cache[5] || (_cache[5] = vue.withModifiers(() => {
1379
1444
  }, ["stop"])),
1380
1445
  onKeydown: [
1381
1446
  vue.withKeys(confirmAdd, ["enter"]),
@@ -1385,10 +1450,10 @@ var __async = (__this, __arguments, generator) => {
1385
1450
  [vue.vModelText, vue.unref(newOptionLabel)]
1386
1451
  ]),
1387
1452
  vue.withDirectives(vue.createElementVNode("input", {
1388
- "onUpdate:modelValue": _cache[7] || (_cache[7] = ($event) => vue.isRef(newOptionKey) ? newOptionKey.value = $event : null),
1453
+ "onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => vue.isRef(newOptionKey) ? newOptionKey.value = $event : null),
1389
1454
  class: "f-select__add-input",
1390
1455
  placeholder: "选项值(可选)",
1391
- onClick: _cache[8] || (_cache[8] = vue.withModifiers(() => {
1456
+ onClick: _cache[7] || (_cache[7] = vue.withModifiers(() => {
1392
1457
  }, ["stop"])),
1393
1458
  onKeydown: [
1394
1459
  vue.withKeys(confirmAdd, ["enter"]),
@@ -1416,18 +1481,18 @@ var __async = (__this, __arguments, generator) => {
1416
1481
  }, vue.toDisplayString(_ctx.addOptionText), 1))
1417
1482
  ])) : vue.createCommentVNode("", true)
1418
1483
  ]),
1419
- _: 1
1484
+ _: 3
1420
1485
  }, 8, ["max-height"])
1421
- ], 4)) : vue.createCommentVNode("", true)
1486
+ ], 14, _hoisted_6$e)) : vue.createCommentVNode("", true)
1422
1487
  ]),
1423
- _: 1
1488
+ _: 3
1424
1489
  })
1425
1490
  ]))
1426
1491
  ], 512);
1427
1492
  };
1428
1493
  }
1429
1494
  });
1430
- const FSelect = /* @__PURE__ */ _export_sfc(_sfc_main$O, [["__scopeId", "data-v-2115ccc5"]]);
1495
+ const FSelect = /* @__PURE__ */ _export_sfc(_sfc_main$O, [["__scopeId", "data-v-42ec0325"]]);
1431
1496
  const _hoisted_1$B = { class: "f-date-picker__inner" };
1432
1497
  const _hoisted_2$w = ["value", "placeholder", "disabled"];
1433
1498
  const _hoisted_3$t = { class: "f-date-picker-panel" };
@@ -5,7 +5,23 @@ type __VLS_Props = FSelectProps;
5
5
  type __VLS_PublicProps = __VLS_Props & {
6
6
  modelValue?: SelectKey | SelectKey[] | null;
7
7
  };
8
- declare const _default: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
8
+ declare var __VLS_8: {
9
+ option: FDropdownOption;
10
+ label: string;
11
+ }, __VLS_39: {
12
+ option: FDropdownOption;
13
+ selected: boolean;
14
+ }, __VLS_41: {}, __VLS_43: {};
15
+ type __VLS_Slots = {} & {
16
+ label?: (props: typeof __VLS_8) => any;
17
+ } & {
18
+ option?: (props: typeof __VLS_39) => any;
19
+ } & {
20
+ empty?: (props: typeof __VLS_41) => any;
21
+ } & {
22
+ footer?: (props: typeof __VLS_43) => any;
23
+ };
24
+ declare const __VLS_component: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
9
25
  "update:modelValue": (value: SelectKey | SelectKey[]) => any;
10
26
  } & {
11
27
  select: (key: SelectKey, option: FDropdownOption) => any;
@@ -23,9 +39,19 @@ declare const _default: import("vue").DefineComponent<__VLS_PublicProps, {}, {},
23
39
  size: "small" | "medium" | "large";
24
40
  placeholder: string;
25
41
  clearable: boolean;
42
+ placement: "auto" | "top" | "bottom";
26
43
  multiple: boolean;
44
+ bordered: boolean;
45
+ minDropdownWidth: number;
46
+ maxDropdownHeight: number;
27
47
  filterable: boolean;
28
48
  showAddOption: boolean;
29
49
  addOptionText: string;
30
50
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
51
+ declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
31
52
  export default _default;
53
+ type __VLS_WithSlots<T, S> = T & {
54
+ new (): {
55
+ $slots: S;
56
+ };
57
+ };
@@ -1,5 +1,11 @@
1
1
  import type { FDropdownOption } from './f-dropdown';
2
2
  export interface FSelectProps {
3
+ bordered?: boolean;
4
+ placement?: 'auto' | 'top' | 'bottom';
5
+ dropdownClass?: string;
6
+ optionClass?: string | ((option: FDropdownOption, selected: boolean) => string);
7
+ minDropdownWidth?: number;
8
+ maxDropdownHeight?: number;
3
9
  /** 选项列表 */
4
10
  options: FDropdownOption[];
5
11
  /** 占位符 */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fantasia-ui",
3
3
  "private": false,
4
- "version": "0.6.6",
4
+ "version": "0.6.7",
5
5
  "type": "module",
6
6
  "main": "dist/fantasia-ui.umd.js",
7
7
  "module": "dist/fantasia-ui.es.js",