@coreui/vue-pro 4.8.0-next.0 → 4.8.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1909,38 +1909,6 @@ const CCardPlugin = {
1909
1909
  },
1910
1910
  };
1911
1911
 
1912
- const getNextSibling = (elem, selector) => {
1913
- // Get the next sibling element
1914
- let sibling = elem.nextElementSibling;
1915
- // If there's no selector, return the first sibling
1916
- if (!selector)
1917
- return sibling;
1918
- // If the sibling matches our selector, use it
1919
- // If not, jump to the next sibling and continue the loop
1920
- while (sibling) {
1921
- if (sibling.matches(selector))
1922
- return sibling;
1923
- sibling = sibling.nextElementSibling;
1924
- }
1925
- return;
1926
- };
1927
-
1928
- const getPreviousSibling = (elem, selector) => {
1929
- // Get the next sibling element
1930
- let sibling = elem.previousElementSibling;
1931
- // If there's no selector, return the first sibling
1932
- if (!selector)
1933
- return sibling;
1934
- // If the sibling matches our selector, use it
1935
- // If not, jump to the next sibling and continue the loop
1936
- while (sibling) {
1937
- if (sibling.matches(selector))
1938
- return sibling;
1939
- sibling = sibling.previousElementSibling;
1940
- }
1941
- return;
1942
- };
1943
-
1944
1912
  const isInViewport = (element) => {
1945
1913
  const rect = element.getBoundingClientRect();
1946
1914
  return (Math.floor(rect.top) >= 0 &&
@@ -11534,6 +11502,159 @@ const CMultiSelectNativeSelect = vue.defineComponent({
11534
11502
  },
11535
11503
  });
11536
11504
 
11505
+ const CVirtualScroller = vue.defineComponent({
11506
+ name: 'CVirtualScroller',
11507
+ props: {
11508
+ /**
11509
+ * Amount of visible items
11510
+ */
11511
+ visibleItems: {
11512
+ type: Number,
11513
+ default: 10,
11514
+ },
11515
+ },
11516
+ setup(props, { slots }) {
11517
+ const virtualScrollRef = vue.ref();
11518
+ const virtualScrollContentRef = vue.ref();
11519
+ const currentItemIndex = vue.ref(1);
11520
+ const itemHeight = vue.ref(0);
11521
+ const itemsNumber = vue.ref(0);
11522
+ const viewportPadding = vue.ref(0);
11523
+ const buffer = vue.computed(() => Math.floor(props.visibleItems / 2));
11524
+ const maxHeight = vue.computed(() => itemsNumber.value * itemHeight.value + 2 * viewportPadding.value);
11525
+ const viewportHeight = vue.computed(() => props.visibleItems * itemHeight.value + 2 * viewportPadding.value);
11526
+ vue.onMounted(() => {
11527
+ if (virtualScrollRef.value) {
11528
+ viewportPadding.value = parseFloat(getComputedStyle(virtualScrollRef.value).paddingTop);
11529
+ // It's necessary to calculate heights of items
11530
+ virtualScrollRef.value.dispatchEvent(new CustomEvent('scroll'));
11531
+ }
11532
+ });
11533
+ const handleScroll = (scrollTop) => {
11534
+ currentItemIndex.value =
11535
+ itemHeight.value && Math.max(Math.ceil(scrollTop / itemHeight.value), 1);
11536
+ };
11537
+ return () => {
11538
+ const children = slots.default
11539
+ ? Array.isArray(slots.default()[0].children)
11540
+ ? slots.default()[0].children
11541
+ : slots.default()
11542
+ : [];
11543
+ itemsNumber.value = children && children.length ? children.length : 0;
11544
+ return vue.h('div', {
11545
+ class: ['virtual-scroller'],
11546
+ onScroll: (event) => handleScroll(event.target.scrollTop),
11547
+ style: {
11548
+ height: `${maxHeight.value > viewportHeight.value ? viewportHeight.value : maxHeight.value}px`,
11549
+ overflowY: 'auto',
11550
+ },
11551
+ ref: virtualScrollRef,
11552
+ }, vue.h('div', {
11553
+ class: 'virtual-scroller-content',
11554
+ style: {
11555
+ height: `${maxHeight.value}px`,
11556
+ },
11557
+ ref: virtualScrollContentRef,
11558
+ }, children.map((slot, index) => index + 1 > Math.max(currentItemIndex.value - buffer.value, 0) &&
11559
+ index + 1 <= currentItemIndex.value + props.visibleItems + buffer.value &&
11560
+ vue.cloneVNode(slot, {
11561
+ class: [
11562
+ {
11563
+ 'virtual-scroller-item-preload': index + 1 > currentItemIndex.value + props.visibleItems ||
11564
+ index + 1 < currentItemIndex.value,
11565
+ },
11566
+ ],
11567
+ style: {
11568
+ ...(currentItemIndex.value > buffer.value && {
11569
+ transform: `translateY(${(currentItemIndex.value - buffer.value) * itemHeight.value}px)`,
11570
+ }),
11571
+ },
11572
+ ref: (node) => {
11573
+ if (node && node.offsetHeight) {
11574
+ itemHeight.value =
11575
+ node.offsetHeight +
11576
+ parseFloat(getComputedStyle(node).marginTop) +
11577
+ parseFloat(getComputedStyle(node).marginBottom);
11578
+ }
11579
+ },
11580
+ }))));
11581
+ };
11582
+ },
11583
+ });
11584
+
11585
+ const CVirtualScrollerPlugin = {
11586
+ install: (app) => {
11587
+ app.component(CVirtualScroller.name, CVirtualScroller);
11588
+ },
11589
+ };
11590
+
11591
+ const filterOptionsList = (search, _options) => {
11592
+ return search.length
11593
+ ? _options &&
11594
+ _options.reduce((acc, val) => {
11595
+ const options = val.options &&
11596
+ val.options.filter((element) => element.text && element.text.toLowerCase().includes(search.toLowerCase()));
11597
+ if ((val.text && val.text.toLowerCase().includes(search.toLowerCase())) ||
11598
+ (options && options.length)) {
11599
+ acc.push(Object.assign({}, val, options && options.length && { options }));
11600
+ }
11601
+ return acc;
11602
+ }, [])
11603
+ : _options;
11604
+ };
11605
+ const flattenArray = (options) => {
11606
+ return options.reduce((acc, val) => {
11607
+ return acc.concat(Array.isArray(val.options) ? flattenArray(val.options) : val);
11608
+ }, []);
11609
+ };
11610
+ const getNextSibling = (elem, selector) => {
11611
+ // Get the next sibling element
11612
+ let sibling = elem.nextElementSibling;
11613
+ // If there's no selector, return the first sibling
11614
+ if (!selector)
11615
+ return sibling;
11616
+ // If the sibling matches our selector, use it
11617
+ // If not, jump to the next sibling and continue the loop
11618
+ while (sibling) {
11619
+ if (sibling.matches(selector))
11620
+ return sibling;
11621
+ sibling = sibling.nextElementSibling;
11622
+ }
11623
+ return;
11624
+ };
11625
+ const getPreviousSibling = (elem, selector) => {
11626
+ // Get the next sibling element
11627
+ let sibling = elem.previousElementSibling;
11628
+ // If there's no selector, return the first sibling
11629
+ if (!selector)
11630
+ return sibling;
11631
+ // If the sibling matches our selector, use it
11632
+ // If not, jump to the next sibling and continue the loop
11633
+ while (sibling) {
11634
+ if (sibling.matches(selector))
11635
+ return sibling;
11636
+ sibling = sibling.previousElementSibling;
11637
+ }
11638
+ return;
11639
+ };
11640
+ const selectOptions = (options, selected, deselected) => {
11641
+ let _selected = [...selected, ...options];
11642
+ if (deselected) {
11643
+ _selected = _selected.filter((selectedOption) => !deselected.some((deselectedOption) => deselectedOption.value === selectedOption.value));
11644
+ }
11645
+ const deduplicated = _selected.reduce((unique, option) => {
11646
+ if (!unique.some((obj) => obj.value === option.value)) {
11647
+ unique.push({
11648
+ value: option.value,
11649
+ text: option.text,
11650
+ ...(option.disabled && { disabled: option.disabled }),
11651
+ });
11652
+ }
11653
+ return unique;
11654
+ }, []);
11655
+ return deduplicated;
11656
+ };
11657
+
11537
11658
  const CMultiSelectOptions = vue.defineComponent({
11538
11659
  name: 'CMultiSelectOptions',
11539
11660
  props: {
@@ -11543,7 +11664,6 @@ const CMultiSelectOptions = vue.defineComponent({
11543
11664
  options: {
11544
11665
  type: Array,
11545
11666
  default: () => [],
11546
- required: false,
11547
11667
  },
11548
11668
  /**
11549
11669
  * Sets maxHeight of options list.
@@ -11553,7 +11673,6 @@ const CMultiSelectOptions = vue.defineComponent({
11553
11673
  optionsMaxHeight: {
11554
11674
  type: [Number, String],
11555
11675
  default: 'auto',
11556
- required: false,
11557
11676
  },
11558
11677
  /**
11559
11678
  * Sets option style.
@@ -11564,7 +11683,6 @@ const CMultiSelectOptions = vue.defineComponent({
11564
11683
  optionsStyle: {
11565
11684
  type: String,
11566
11685
  default: 'checkbox',
11567
- required: false,
11568
11686
  validator: (value) => {
11569
11687
  return ['checkbox', 'text'].includes(value);
11570
11688
  },
@@ -11575,12 +11693,15 @@ const CMultiSelectOptions = vue.defineComponent({
11575
11693
  searchNoResultsLabel: {
11576
11694
  type: String,
11577
11695
  default: 'no items',
11578
- required: false,
11579
11696
  },
11580
11697
  selected: {
11581
11698
  type: Array,
11582
11699
  default: () => [],
11583
- required: false,
11700
+ },
11701
+ virtualScroller: Boolean,
11702
+ visibleItems: {
11703
+ type: Number,
11704
+ default: 10,
11584
11705
  },
11585
11706
  },
11586
11707
  emits: ['optionClick'],
@@ -11632,12 +11753,19 @@ const CMultiSelectOptions = vue.defineComponent({
11632
11753
  tabindex: 0,
11633
11754
  }, option.text))
11634
11755
  : vue.h('div', { class: 'form-multi-select-options-empty' }, props.searchNoResultsLabel);
11635
- return () => vue.h('div', {
11636
- class: 'form-multi-select-options',
11637
- ...(props.optionsMaxHeight !== 'auto' && {
11638
- style: { maxHeight: props.optionsMaxHeight, overflow: 'scroll' },
11639
- }),
11640
- }, createOptions(props.options));
11756
+ return () => props.virtualScroller
11757
+ ? vue.h(CVirtualScroller, {
11758
+ class: 'form-multi-select-options',
11759
+ visibleItems: props.visibleItems,
11760
+ }, {
11761
+ default: () => createOptions(props.options),
11762
+ })
11763
+ : vue.h('div', {
11764
+ class: 'form-multi-select-options',
11765
+ ...(props.optionsMaxHeight !== 'auto' && {
11766
+ style: { maxHeight: props.optionsMaxHeight, overflow: 'scroll' },
11767
+ }),
11768
+ }, createOptions(props.options));
11641
11769
  },
11642
11770
  });
11643
11771
 
@@ -11728,11 +11856,6 @@ const CMultiSelectSelection = vue.defineComponent({
11728
11856
  },
11729
11857
  });
11730
11858
 
11731
- const flattenArray = (options) => {
11732
- return options.reduce((acc, val) => {
11733
- return acc.concat(Array.isArray(val.options) ? flattenArray(val.options) : val);
11734
- }, []);
11735
- };
11736
11859
  const CMultiSelect = vue.defineComponent({
11737
11860
  name: 'CMultiSelect',
11738
11861
  props: {
@@ -11743,7 +11866,6 @@ const CMultiSelect = vue.defineComponent({
11743
11866
  */
11744
11867
  cleaner: {
11745
11868
  type: Boolean,
11746
- required: false,
11747
11869
  default: true,
11748
11870
  },
11749
11871
  /**
@@ -11751,7 +11873,6 @@ const CMultiSelect = vue.defineComponent({
11751
11873
  */
11752
11874
  disabled: {
11753
11875
  type: Boolean,
11754
- required: false,
11755
11876
  default: false,
11756
11877
  },
11757
11878
  /**
@@ -11806,7 +11927,6 @@ const CMultiSelect = vue.defineComponent({
11806
11927
  multiple: {
11807
11928
  type: Boolean,
11808
11929
  default: true,
11809
- required: false,
11810
11930
  },
11811
11931
  /**
11812
11932
  * List of option elements.
@@ -11814,7 +11934,6 @@ const CMultiSelect = vue.defineComponent({
11814
11934
  options: {
11815
11935
  type: Array,
11816
11936
  default: () => [],
11817
- required: false,
11818
11937
  },
11819
11938
  /**
11820
11939
  * Sets maxHeight of options list.
@@ -11824,7 +11943,6 @@ const CMultiSelect = vue.defineComponent({
11824
11943
  optionsMaxHeight: {
11825
11944
  type: [Number, String],
11826
11945
  default: 'auto',
11827
- required: false,
11828
11946
  },
11829
11947
  /**
11830
11948
  * Sets option style.
@@ -11835,7 +11953,6 @@ const CMultiSelect = vue.defineComponent({
11835
11953
  optionsStyle: {
11836
11954
  type: String,
11837
11955
  default: 'checkbox',
11838
- required: false,
11839
11956
  validator: (value) => {
11840
11957
  return ['checkbox', 'text'].includes(value);
11841
11958
  },
@@ -11848,7 +11965,6 @@ const CMultiSelect = vue.defineComponent({
11848
11965
  placeholder: {
11849
11966
  type: String,
11850
11967
  default: 'Select...',
11851
- required: false,
11852
11968
  },
11853
11969
  /**
11854
11970
  * Enables search input element.
@@ -11856,7 +11972,6 @@ const CMultiSelect = vue.defineComponent({
11856
11972
  search: {
11857
11973
  type: [Boolean, String],
11858
11974
  default: true,
11859
- required: false,
11860
11975
  validator: (value) => {
11861
11976
  if (typeof value == 'string') {
11862
11977
  return ['external'].includes(value);
@@ -11873,7 +11988,6 @@ const CMultiSelect = vue.defineComponent({
11873
11988
  searchNoResultsLabel: {
11874
11989
  type: String,
11875
11990
  default: 'no items',
11876
- required: false,
11877
11991
  },
11878
11992
  /**
11879
11993
  * Enables select all button.
@@ -11882,7 +11996,6 @@ const CMultiSelect = vue.defineComponent({
11882
11996
  */
11883
11997
  selectAll: {
11884
11998
  type: Boolean,
11885
- required: false,
11886
11999
  default: true,
11887
12000
  },
11888
12001
  /**
@@ -11892,7 +12005,6 @@ const CMultiSelect = vue.defineComponent({
11892
12005
  */
11893
12006
  selectAllLabel: {
11894
12007
  type: String,
11895
- required: false,
11896
12008
  default: 'Select all options',
11897
12009
  },
11898
12010
  /**
@@ -11904,7 +12016,6 @@ const CMultiSelect = vue.defineComponent({
11904
12016
  selectionType: {
11905
12017
  type: String,
11906
12018
  default: 'tags',
11907
- required: false,
11908
12019
  validator: (value) => {
11909
12020
  return ['counter', 'tags', 'text'].includes(value);
11910
12021
  },
@@ -11917,7 +12028,6 @@ const CMultiSelect = vue.defineComponent({
11917
12028
  selectionTypeCounterText: {
11918
12029
  type: String,
11919
12030
  default: 'item(s) selected',
11920
- required: false,
11921
12031
  },
11922
12032
  /**
11923
12033
  * Size the component small or large.
@@ -11926,7 +12036,6 @@ const CMultiSelect = vue.defineComponent({
11926
12036
  */
11927
12037
  size: {
11928
12038
  type: String,
11929
- required: false,
11930
12039
  validator: (value) => {
11931
12040
  return ['sm', 'lg'].includes(value);
11932
12041
  },
@@ -11951,6 +12060,12 @@ const CMultiSelect = vue.defineComponent({
11951
12060
  * @since 4.6.0
11952
12061
  */
11953
12062
  valid: Boolean,
12063
+ /**
12064
+ * Enable virtual scroller for the options list.
12065
+ *
12066
+ * @since 4.8.0
12067
+ */
12068
+ virtualScroller: Boolean,
11954
12069
  /**
11955
12070
  * Toggle the visibility of multi select dropdown.
11956
12071
  *
@@ -11959,7 +12074,16 @@ const CMultiSelect = vue.defineComponent({
11959
12074
  visible: {
11960
12075
  type: Boolean,
11961
12076
  default: false,
11962
- required: false,
12077
+ },
12078
+ /**
12079
+ *
12080
+ * Amount of visible items when virtualScroller is set to `true`.
12081
+ *
12082
+ * @since 4.8.0
12083
+ */
12084
+ visibleItems: {
12085
+ type: Number,
12086
+ default: 10,
11963
12087
  },
11964
12088
  },
11965
12089
  emits: [
@@ -11976,29 +12100,12 @@ const CMultiSelect = vue.defineComponent({
11976
12100
  ],
11977
12101
  setup(props, { attrs, emit }) {
11978
12102
  const nativeSelectRef = vue.ref();
11979
- vue.provide('nativeSelectRef', nativeSelectRef);
11980
- const searchRef = vue.ref();
11981
12103
  const options = vue.ref(props.options);
11982
12104
  const search = vue.ref('');
12105
+ const searchRef = vue.ref();
11983
12106
  const selected = vue.ref([]);
11984
12107
  const visible = vue.ref(props.visible);
11985
- const selectOptions = (options, deselected) => {
11986
- let _selected = [...selected.value, ...options];
11987
- if (deselected) {
11988
- _selected = _selected.filter((selectedOption) => !deselected.some((deselectedOption) => deselectedOption.value === selectedOption.value));
11989
- }
11990
- const deduplicated = _selected.reduce((unique, option) => {
11991
- if (!unique.some((obj) => obj.value === option.value)) {
11992
- unique.push({
11993
- value: option.value,
11994
- text: option.text,
11995
- ...(option.disabled && { disabled: option.disabled }),
11996
- });
11997
- }
11998
- return unique;
11999
- }, []);
12000
- selected.value = deduplicated;
12001
- };
12108
+ vue.provide('nativeSelectRef', nativeSelectRef);
12002
12109
  vue.watch(() => props.options, (newValue, oldValue) => {
12003
12110
  if (JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
12004
12111
  options.value = newValue;
@@ -12016,27 +12123,15 @@ const CMultiSelect = vue.defineComponent({
12016
12123
  }
12017
12124
  return;
12018
12125
  });
12019
- _selected && selectOptions(_selected, deselected);
12126
+ if (_selected) {
12127
+ selected.value = selectOptions(_selected, selected.value, deselected);
12128
+ }
12020
12129
  }
12021
- });
12130
+ }, { immediate: true });
12022
12131
  vue.watch(selected, () => {
12023
12132
  nativeSelectRef.value &&
12024
12133
  nativeSelectRef.value.dispatchEvent(new Event('change', { bubbles: true }));
12025
12134
  });
12026
- const filterOptionsList = (search, _options) => {
12027
- return search.length
12028
- ? _options &&
12029
- _options.reduce((acc, val) => {
12030
- const options = val.options &&
12031
- val.options.filter((element) => element.text && element.text.toLowerCase().includes(search.toLowerCase()));
12032
- if ((val.text && val.text.toLowerCase().includes(search.toLowerCase())) ||
12033
- (options && options.length)) {
12034
- acc.push(Object.assign({}, val, options && options.length && { options }));
12035
- }
12036
- return acc;
12037
- }, [])
12038
- : options.value;
12039
- };
12040
12135
  const handleSearchChange = (event) => {
12041
12136
  const target = event.target;
12042
12137
  search.value = target.value.toLowerCase();
@@ -12074,7 +12169,7 @@ const CMultiSelect = vue.defineComponent({
12074
12169
  }
12075
12170
  };
12076
12171
  const handleSelectAll = () => {
12077
- selectOptions(flattenArray(options.value).filter((option) => !option.disabled));
12172
+ selected.value = selectOptions(flattenArray(options.value).filter((option) => !option.disabled), selected.value);
12078
12173
  };
12079
12174
  const handleDeselectAll = () => {
12080
12175
  selected.value = selected.value.filter((option) => option.disabled);
@@ -12165,7 +12260,7 @@ const CMultiSelect = vue.defineComponent({
12165
12260
  ref: searchRef,
12166
12261
  }),
12167
12262
  ]),
12168
- default: () => vue.h('div', {}, [
12263
+ default: () => visible.value && [
12169
12264
  props.multiple &&
12170
12265
  props.selectAll &&
12171
12266
  vue.h('button', {
@@ -12181,9 +12276,11 @@ const CMultiSelect = vue.defineComponent({
12181
12276
  optionsMaxHeight: props.optionsMaxHeight,
12182
12277
  optionsStyle: props.optionsStyle,
12183
12278
  searchNoResultsLabel: props.searchNoResultsLabel,
12184
- selected: selected.value
12279
+ selected: selected.value,
12280
+ virtualScroller: props.virtualScroller,
12281
+ visibleItems: props.visibleItems,
12185
12282
  }),
12186
- ]),
12283
+ ],
12187
12284
  }),
12188
12285
  }),
12189
12286
  ];
@@ -16688,6 +16785,8 @@ var Components = /*#__PURE__*/Object.freeze({
16688
16785
  CToaster: CToaster,
16689
16786
  CTooltip: CTooltip,
16690
16787
  CTooltipPlugin: CTooltipPlugin,
16788
+ CVirtualScroller: CVirtualScroller,
16789
+ CVirtualScrollerPlugin: CVirtualScrollerPlugin,
16691
16790
  CWidgetStatsA: CWidgetStatsA,
16692
16791
  CWidgetStatsB: CWidgetStatsB,
16693
16792
  CWidgetStatsC: CWidgetStatsC,
@@ -17096,6 +17195,8 @@ exports.CToastPlugin = CToastPlugin;
17096
17195
  exports.CToaster = CToaster;
17097
17196
  exports.CTooltip = CTooltip;
17098
17197
  exports.CTooltipPlugin = CTooltipPlugin;
17198
+ exports.CVirtualScroller = CVirtualScroller;
17199
+ exports.CVirtualScrollerPlugin = CVirtualScrollerPlugin;
17099
17200
  exports.CWidgetStatsA = CWidgetStatsA;
17100
17201
  exports.CWidgetStatsB = CWidgetStatsB;
17101
17202
  exports.CWidgetStatsC = CWidgetStatsC;