@eturnity/eturnity_reusable_components 9.16.0 → 9.19.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eturnity/eturnity_reusable_components",
3
- "version": "9.16.0",
3
+ "version": "9.19.0",
4
4
  "files": [
5
5
  "dist",
6
6
  "src"
@@ -30,6 +30,7 @@
30
30
  "@vueform/slider": "2.1.10",
31
31
  "@vuepic/vue-datepicker": "6.1.0",
32
32
  "click-outside-vue3": "4.0.1",
33
+ "date-fns": "^4.1.0",
33
34
  "storybook": "8.2.9",
34
35
  "vite-plugin-require": "1.1.14",
35
36
  "vue": "3.3.4",
@@ -1,6 +1,35 @@
1
1
  <template>
2
2
  <ContainerWrapper @click="$emit('on-container-click')">
3
3
  <UpperContainer v-if="filterViews && filterViews.length">
4
+ <ViewContainer v-if="showActiveFilter" :max-width="activeView.length">
5
+ <SelectComponent
6
+ align-items="vertical"
7
+ :data-id="componentName + '_filter_view_select'"
8
+ :data-qa-id="componentName + '_filter_view_select'"
9
+ font-size="13px"
10
+ :label="$gettext('active_filter')"
11
+ select-height="36px"
12
+ select-width="100%"
13
+ @click.stop
14
+ >
15
+ <template #selector>
16
+ <OptionTitle>
17
+ {{ activeView }}
18
+ </OptionTitle>
19
+ </template>
20
+ <template #dropdown>
21
+ <Option
22
+ v-for="(item, idx) in filterViews"
23
+ :key="idx + '_view'"
24
+ :value="item.name"
25
+ @click="$emit('on-view-select', item)"
26
+ >
27
+ {{ item.name }}
28
+ <DeleteIcon @click.stop="$emit('on-view-delete', item)" />
29
+ </Option>
30
+ </template>
31
+ </SelectComponent>
32
+ </ViewContainer>
4
33
  <ResetButton
5
34
  :data-id="componentName + '_reset_filters_button'"
6
35
  :data-qa-id="componentName + '_reset_filters_button'"
@@ -76,15 +105,16 @@
76
105
  align-items="vertical"
77
106
  :data-id="componentName + '_' + filter.field + '_select'"
78
107
  :data-qa-id="componentName + '_' + filter.field + '_select'"
108
+ :defer-dropdown-slot-content="true"
79
109
  :disabled="!filter.choices.length"
80
110
  font-size="13px"
81
- :is-searchable="filter.choices.length > 7"
111
+ :is-searchable="filter.choices.length > 5"
82
112
  :label="filter.label"
83
113
  :label-data-id="filter.dataId"
84
- lazy-dropdown-content
85
114
  :min-option-length="1"
86
115
  select-height="36px"
87
116
  select-width="100%"
117
+ :should-use-teleport="true"
88
118
  >
89
119
  <template #selector>
90
120
  <OptionTitle> {{ filter.selectedText }} </OptionTitle>
@@ -236,7 +266,7 @@
236
266
  model-type="format"
237
267
  :model-value="filter.range.start"
238
268
  :placeholder="$gettext('Date from')"
239
- teleport="body"
269
+ :teleport="true"
240
270
  text-input
241
271
  @close="onDatepickerBlur()"
242
272
  @focus="onDatepickerFocus(filter.range)"
@@ -266,7 +296,7 @@
266
296
  model-type="format"
267
297
  :model-value="filter.range.end"
268
298
  :placeholder="$gettext('Date to')"
269
- teleport="body"
299
+ :teleport="true"
270
300
  text-input
271
301
  @close="onDatepickerBlur()"
272
302
  @focus="onDatepickerFocus(filter.range)"
@@ -286,13 +316,14 @@
286
316
  align-items="vertical"
287
317
  :data-id="componentName + '_' + filter.field + '_select'"
288
318
  :data-qa-id="componentName + '_' + filter.field + '_select'"
319
+ :defer-dropdown-slot-content="true"
289
320
  :disabled="!filter.choices.length"
290
321
  font-size="13px"
291
- :is-searchable="filter.choices.length > 7"
322
+ :is-searchable="filter.choices.length > 5"
292
323
  :label="filter.label"
293
- lazy-dropdown-content
294
324
  select-height="36px"
295
325
  select-width="100%"
326
+ :should-use-teleport="true"
296
327
  >
297
328
  <template #selector="{ selectedValue }">
298
329
  <OptionTitle>
@@ -574,6 +605,10 @@
574
605
  VueDatePicker,
575
606
  },
576
607
  props: {
608
+ showActiveFilter: {
609
+ required: false,
610
+ default: true,
611
+ },
577
612
  filterData: {
578
613
  required: true,
579
614
  },
@@ -726,7 +761,11 @@
726
761
  )
727
762
  },
728
763
  isRangeSelector(type) {
729
- return type === 'integer_range' || type === 'number_range'
764
+ return (
765
+ type === 'integer_range' ||
766
+ type === 'number_range' ||
767
+ type === 'float_range'
768
+ )
730
769
  },
731
770
  isIntegerRange(type) {
732
771
  return type === 'integer_range'
@@ -18,6 +18,7 @@
18
18
  :filter-views="filterViews"
19
19
  :has-active-view="hasActiveView"
20
20
  :settings-translations="settingsTranslations"
21
+ :show-active-filter="showActiveFilter"
21
22
  @on-apply-current-view="onApplyCurrentView()"
22
23
  @on-cancel-view="onCancelSettings()"
23
24
  @on-container-click="onContainerClick()"
@@ -83,6 +84,11 @@
83
84
  default: null,
84
85
  required: false,
85
86
  },
87
+ showActiveFilter: {
88
+ required: false,
89
+ default: true,
90
+ type: Boolean,
91
+ },
86
92
  /** Host store slice (e.g. getCurrentFilterData) so the badge tracks live `filters`. */
87
93
  currentFilterData: {
88
94
  type: Object,
@@ -92,6 +98,7 @@
92
98
  componentName: {
93
99
  type: String,
94
100
  required: false,
101
+ default: null,
95
102
  },
96
103
  },
97
104
  data() {
@@ -224,10 +224,16 @@
224
224
  `
225
225
  &:hover svg path:not(.fix, .isStrokePath) {
226
226
  ${`${props.fillType}: ${
227
- props.theme.colors[props.hoveredColor] || props.color
227
+ props.theme.colors[props.hoveredColor] ||
228
+ props.hoveredColor ||
229
+ props.color
228
230
  };`}
229
231
  &:hover svg isStrokePath:not(.fix) {
230
- ${`stroke: ${props.theme.colors[props.hoveredColor] || props.color};`}
232
+ ${`stroke: ${
233
+ props.theme.colors[props.hoveredColor] ||
234
+ props.hoveredColor ||
235
+ props.color
236
+ };`}
231
237
  }
232
238
  &:hover + div {
233
239
  background-color: ${props.hoveredColor};
@@ -252,10 +252,15 @@
252
252
  },
253
253
  computed: {
254
254
  hasLabel() {
255
- if (this.label == null || this.label === '') {
255
+ const label = this.label
256
+ if (label === null || label === undefined || label === '') {
256
257
  return false
257
258
  }
258
- return String(this.label).length > 0
259
+ if (typeof label === 'string') {
260
+ return label.length > 0
261
+ }
262
+ // numbers and other primitives: .length is undefined on numbers (e.g. year 2023)
263
+ return true
259
264
  },
260
265
  },
261
266
  methods: {
@@ -198,10 +198,10 @@
198
198
  @option-hovered="optionHovered"
199
199
  @option-selected="optionSelected"
200
200
  >
201
- <!-- When lazy, skip building option/checkbox nodes until the user opens
202
- this select (filter settings can have thousands of options otherwise). -->
201
+ <!-- When deferDropdownSlotContent is true, slot VNodes are not created until the
202
+ dropdown opens avoids mounting huge option lists (e.g. library filters). -->
203
203
  <slot
204
- v-if="!lazyDropdownContent || isDropdownOpen"
204
+ v-if="!deferDropdownSlotContent || isSelectDropdownShown"
205
205
  name="dropdown"
206
206
  ></slot>
207
207
  </SelectDropdown>
@@ -732,7 +732,7 @@
732
732
  default: true,
733
733
  },
734
734
  /** If true, dropdown slot content is only rendered while the menu is open. */
735
- lazyDropdownContent: {
735
+ deferDropdownSlotContent: {
736
736
  type: Boolean,
737
737
  required: false,
738
738
  default: false,
@@ -765,6 +765,7 @@
765
765
  selectTopPosition: 0,
766
766
  selectAndDropdownDistance: 0,
767
767
  animationFrameId: null,
768
+ optionLengthCount: 0,
768
769
  }
769
770
  },
770
771
  computed: {
@@ -772,15 +773,7 @@
772
773
  return this.errorMessage && this.errorMessage.length > 0
773
774
  },
774
775
  optionLength() {
775
- if (this.isDropdownOpen) {
776
- return this.$refs.dropdown.$el.childElementCount > 1
777
- ? this.$refs.dropdown.$el.childElementCount
778
- : this.$refs.dropdown.$el.children[0]
779
- ? this.$refs.dropdown.$el.children[0].childElementCount
780
- : 0
781
- }
782
-
783
- return 0
776
+ return this.optionLengthCount
784
777
  },
785
778
  isSearchBarVisible() {
786
779
  return (
@@ -841,9 +834,13 @@
841
834
  }, 10)
842
835
  await this.$nextTick()
843
836
  this.handleSetDropdownOffet()
837
+ this.refreshOptionLength()
844
838
  if (!this.isFixedDropdownPosition) this.calculateSelectTopPosition()
839
+ // Deferred dropdown slot content mounts after initial open in some hosts.
840
+ this.$nextTick(() => this.refreshOptionLength())
845
841
  } else {
846
842
  this.dropdownPosition.left = null
843
+ this.optionLengthCount = 0
847
844
  if (this.animationFrameId) {
848
845
  cancelAnimationFrame(this.animationFrameId)
849
846
  this.animationFrameId = null
@@ -865,6 +862,7 @@
865
862
  // Need to wait for 1ms to make sure the dropdown menu is shown in the DOM
866
863
  // before getting the distance between the select and the dropdown menu
867
864
  setTimeout(() => {
865
+ this.refreshOptionLength()
868
866
  this.getDistanceBetweenSelectAndDropdownMenu()
869
867
  }, 100)
870
868
  },
@@ -967,6 +965,21 @@
967
965
  el.style.display = 'inherit'
968
966
  })
969
967
  },
968
+ refreshOptionLength() {
969
+ const dropdownRef = this.$refs.dropdown
970
+ if (!dropdownRef || !dropdownRef.$el) {
971
+ this.optionLengthCount = 0
972
+ return
973
+ }
974
+ const dropdownEl = dropdownRef.$el
975
+ if (dropdownEl.childElementCount > 1) {
976
+ this.optionLengthCount = dropdownEl.childElementCount
977
+ return
978
+ }
979
+ this.optionLengthCount = dropdownEl.children[0]
980
+ ? dropdownEl.children[0].childElementCount
981
+ : 0
982
+ },
970
983
  clickOutside(event) {
971
984
  const dropdownRef = this.$refs.dropdown
972
985
  if (!this.isClickOutsideActive) return