@ouestfrance/sipa-bms-ui 8.6.0 → 8.8.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 (62) hide show
  1. package/dist/components/form/BmsAutocomplete.vue.d.ts +2 -0
  2. package/dist/components/form/BmsInputBooleanCheckbox.vue.d.ts +1 -1
  3. package/dist/components/form/BmsInputCheckboxGroup.vue.d.ts +2 -2
  4. package/dist/components/form/BmsInputCode.vue.d.ts +2 -2
  5. package/dist/components/form/BmsInputNumber.vue.d.ts +2 -2
  6. package/dist/components/form/BmsInputRadio.vue.d.ts +2 -2
  7. package/dist/components/form/BmsInputText.vue.d.ts +24 -22
  8. package/dist/components/form/BmsMultiSelect.vue.d.ts +3 -1
  9. package/dist/components/form/BmsSearch.vue.d.ts +28 -24
  10. package/dist/components/form/BmsSelect.vue.d.ts +7 -17
  11. package/dist/components/form/RawAutocomplete.vue.d.ts +17 -21
  12. package/dist/components/form/RawInputText.vue.d.ts +9 -9
  13. package/dist/components/form/RawSelect.vue.d.ts +30 -0
  14. package/dist/components/navigation/UiTenantSwitcher.vue.d.ts +28 -24
  15. package/dist/components/table/BmsServerTable.vue.d.ts +18 -0
  16. package/dist/components/table/BmsTable.vue.d.ts +18 -1
  17. package/dist/components/table/BmsTableFilters.vue.d.ts +47 -25
  18. package/dist/composables/search.composable.d.ts +1 -0
  19. package/dist/mockServiceWorker.js +16 -12
  20. package/dist/plugins/field/FieldDatalist.vue.d.ts +2 -0
  21. package/dist/plugins/field/field-component.model.d.ts +2 -2
  22. package/dist/sipa-bms-ui.css +220 -168
  23. package/dist/sipa-bms-ui.es.js +729 -524
  24. package/dist/sipa-bms-ui.es.js.map +1 -1
  25. package/dist/sipa-bms-ui.umd.js +734 -529
  26. package/dist/sipa-bms-ui.umd.js.map +1 -1
  27. package/package.json +11 -11
  28. package/src/assets/scss/global-variables.scss +6 -0
  29. package/src/components/feedback/UiTooltip.vue +1 -1
  30. package/src/components/form/BmsAutocomplete.vue +3 -0
  31. package/src/components/form/BmsInputNumber.spec.ts +26 -0
  32. package/src/components/form/BmsInputNumber.stories.js +20 -3
  33. package/src/components/form/BmsInputNumber.vue +36 -4
  34. package/src/components/form/BmsInputRadio.vue +1 -1
  35. package/src/components/form/BmsInputText.spec.ts +25 -0
  36. package/src/components/form/BmsInputText.stories.js +28 -3
  37. package/src/components/form/BmsInputText.vue +73 -12
  38. package/src/components/form/BmsMultiSelect.vue +66 -28
  39. package/src/components/form/BmsSelect.vue +60 -57
  40. package/src/components/form/RawAutocomplete.spec.ts +0 -8
  41. package/src/components/form/RawAutocomplete.vue +42 -24
  42. package/src/components/form/RawInputText.vue +14 -21
  43. package/src/components/form/RawSelect.vue +111 -0
  44. package/src/components/layout/BmsOverlay.vue +2 -2
  45. package/src/components/layout/UiPopoverMenu.vue +1 -1
  46. package/src/components/navigation/BmsMenu.vue +1 -1
  47. package/src/components/table/BmsServerTable.vue +18 -3
  48. package/src/components/table/BmsTable.vue +15 -2
  49. package/src/components/table/BmsTableFilters.vue +19 -7
  50. package/src/composables/search.composable.spec.ts +75 -0
  51. package/src/composables/search.composable.ts +54 -11
  52. package/src/plugins/field/FieldComponent.vue +7 -5
  53. package/src/plugins/field/FieldDatalist.stories.js +0 -9
  54. package/src/plugins/field/FieldDatalist.vue +16 -13
  55. package/src/plugins/field/field-component.model.ts +2 -2
  56. package/src/plugins/notifications/NotificationWidget.vue +1 -1
  57. package/src/showroom/pages/autocomplete.vue +22 -1
  58. package/src/showroom/pages/server-table.vue +53 -22
  59. package/src/showroom/pages/table.vue +42 -3
  60. package/src/showroom/pages/zindex.vue +39 -0
  61. package/dist/plugins/field/FieldDatalist.spec.d.ts +0 -1
  62. package/src/plugins/field/FieldDatalist.spec.ts +0 -35
@@ -133,7 +133,7 @@ const listener = () => {
133
133
  width: var(--ui-menu-width, auto);
134
134
  width: 400px;
135
135
  position: fixed;
136
- z-index: 10;
136
+ z-index: var(--bms-z-index-fixed);
137
137
  display: block;
138
138
  pointer-events: none;
139
139
  opacity: 0;
@@ -96,7 +96,7 @@ const toggleMenu = (newMenuState: boolean = true) =>
96
96
  margin: 1.5rem;
97
97
  padding: 0;
98
98
  border-radius: 0.5rem;
99
- z-index: 10;
99
+ z-index: var(--bms-z-index-fixed);
100
100
  }
101
101
 
102
102
  &__copyright {
@@ -4,7 +4,10 @@ import BmsPagination from '@/components/table/BmsPagination.vue';
4
4
  import UiBmsTable from '@/components/table/UiBmsTable.vue';
5
5
  import UiFilterButton from '@/components/table/UiFilterButton.vue';
6
6
  import { usePagination } from '@/composables/pagination.composable';
7
- import { useSearch } from '@/composables/search.composable';
7
+ import {
8
+ reflectFiltersToPath,
9
+ useSearch,
10
+ } from '@/composables/search.composable';
8
11
  import { useSort } from '@/composables/sort.composable';
9
12
  import {
10
13
  Filter,
@@ -151,12 +154,15 @@ const {
151
154
  isSavedFilterActive,
152
155
  resetFilters,
153
156
  selectSavedFilter,
157
+ updateFiltersFromProps,
154
158
  } = useSearch(props.persistent, props.filters, props.defaultFiltersOpened);
155
159
 
156
160
  const emits = defineEmits<{
157
161
  deleteSavedFilter: [value: SavedFilter];
158
162
  saveFilter: [value: SavedFilter];
159
163
  'update:selectMode': [selectMode: SelectMode];
164
+ filterInput: [{ filterKey: string; value: any; e: InputEvent }];
165
+ filterChange: [{ filterKey: string; value: any }];
160
166
  }>();
161
167
 
162
168
  const loading = ref<boolean>(false);
@@ -196,6 +202,14 @@ watch([currentPage, isMounting], () => {
196
202
  fetchData();
197
203
  }
198
204
  });
205
+ watch(
206
+ () => props.filters,
207
+ () => {
208
+ updateFiltersFromProps(props.filters);
209
+ reflectFiltersToPath(filters.value);
210
+ },
211
+ { deep: true },
212
+ );
199
213
 
200
214
  watch(
201
215
  [() => filters.value, () => sort.value, size, search],
@@ -324,8 +338,9 @@ const onSelectAll = () => emits('update:selectMode', SelectMode.ALL);
324
338
  :canSaveFilters="canSaveFilters"
325
339
  @saveFilter="onSaveFilter"
326
340
  @resetFilters="resetFilters"
327
- >
328
- </BmsTableFilters>
341
+ @filterInput="(filterEvent) => emits('filterInput', filterEvent)"
342
+ @filterChange="(filterEvent) => emits('filterChange', filterEvent)"
343
+ />
329
344
  </div>
330
345
  </Transition>
331
346
  </template>
@@ -85,11 +85,14 @@ const {
85
85
  resetFilters,
86
86
  selectSavedFilter,
87
87
  resetAllFilters,
88
+ updateFiltersFromProps,
88
89
  } = useSearch(props.persistent, props.filters, props.defaultFiltersOpened);
89
90
 
90
91
  const emits = defineEmits<{
91
- (e: 'deleteSavedFilter', value: SavedFilter): void;
92
- (e: 'saveFilter', value: SavedFilter): void;
92
+ deleteSavedFilter: [value: SavedFilter];
93
+ saveFilter: [value: SavedFilter];
94
+ filterInput: [{ filterKey: string; value: any; e: InputEvent }];
95
+ filterChange: [{ filterKey: string; value: any }];
93
96
  }>();
94
97
 
95
98
  const selectedItems: Ref<unknown[]> = defineModel('selectedItems', {
@@ -116,6 +119,14 @@ const getFilteredItems = () => {
116
119
 
117
120
  const isMounting = ref(true);
118
121
 
122
+ watch(
123
+ () => props.filters,
124
+ () => {
125
+ updateFiltersFromProps(props.filters);
126
+ },
127
+ { deep: true },
128
+ );
129
+
119
130
  watchEffect(
120
131
  async () => {
121
132
  isMounting.value =
@@ -237,6 +248,8 @@ const onSelectAll = () => {
237
248
  :canSaveFilters="canSaveFilters"
238
249
  @saveFilter="onSaveFilter"
239
250
  @reset-filters="resetFilters"
251
+ @filterInput="(filterEvent) => emits('filterInput', filterEvent)"
252
+ @filterChange="(filterEvent) => emits('filterChange', filterEvent)"
240
253
  />
241
254
  </div>
242
255
  </Transition>
@@ -51,6 +51,14 @@
51
51
  "
52
52
  :valueTo="transformValueForComponent(filter?.valueTo, filter.type)"
53
53
  :options="getFilterOptions(filter) as any"
54
+ @input="
55
+ (e: InputEvent) =>
56
+ $emits('filterInput', {
57
+ filterKey: filter.key,
58
+ value: (e.target as HTMLInputElement).value,
59
+ e,
60
+ })
61
+ "
54
62
  />
55
63
  </span>
56
64
  </div>
@@ -101,9 +109,11 @@ const props = withDefaults(
101
109
  );
102
110
 
103
111
  const $emits = defineEmits<{
104
- (e: 'update:modelValue', filters: Filter[]): void;
105
- (e: 'saveFilter', value: SavedFilter): void;
106
- (e: 'resetFilters'): void;
112
+ 'update:modelValue': [filters: Filter[]];
113
+ saveFilter: [value: SavedFilter];
114
+ resetFilters: [];
115
+ filterInput: [{ filterKey: string; value: any; e: InputEvent }];
116
+ filterChange: [{ filterKey: string; value: any }];
107
117
  }>();
108
118
 
109
119
  const savedModalOpened: Ref<boolean> = ref<boolean>(false);
@@ -112,10 +122,11 @@ const nameInput: Ref<typeof BmsInputText | null> = ref(null);
112
122
 
113
123
  const onFilter = (key: string, inputValue: string, valueKey: any): void => {
114
124
  let filter = props.modelValue.find((f) => f.key === key);
125
+ let updatedValue;
115
126
  if (filter) {
116
127
  switch (filter.type) {
117
128
  case 'boolean':
118
- filter.value =
129
+ updatedValue =
119
130
  inputValue === 'true' ? true : inputValue === 'false' ? false : null;
120
131
  break;
121
132
  case 'select':
@@ -123,13 +134,14 @@ const onFilter = (key: string, inputValue: string, valueKey: any): void => {
123
134
  case 'betweenDate':
124
135
  case 'betweenDateTime':
125
136
  case 'betweenNumber':
126
- filter[valueKey as keyof Filter] =
127
- inputValue === 'null' ? null : inputValue;
137
+ updatedValue = inputValue === 'null' ? null : inputValue;
128
138
  break;
129
139
  default:
130
- filter.value = inputValue;
140
+ updatedValue = inputValue;
131
141
  break;
132
142
  }
143
+ filter[valueKey as keyof Filter] = updatedValue;
144
+ $emits('filterChange', { filterKey: key, value: updatedValue });
133
145
  }
134
146
  $emits('update:modelValue', props.modelValue);
135
147
  };
@@ -6,6 +6,7 @@ import {
6
6
  } from './search.composable';
7
7
  import { defineComponent, nextTick } from 'vue';
8
8
  import { mount } from '@vue/test-utils';
9
+ import { Filter } from '@/models';
9
10
 
10
11
  vi.mock('vue-router', () => ({
11
12
  useRoute: vi.fn(),
@@ -1292,5 +1293,79 @@ describe('search and filter composable', () => {
1292
1293
  ]);
1293
1294
  });
1294
1295
  });
1296
+
1297
+ describe('updateFiltersFromProps', () => {
1298
+ test('should update select options', () => {
1299
+ const wrapper = factory();
1300
+ const filter: Filter = {
1301
+ key: 'filter0',
1302
+ label: 'Zéro',
1303
+ type: 'select',
1304
+ selectOptions: [{ label: 'option1', value: '1' }],
1305
+ value: 1,
1306
+ };
1307
+
1308
+ wrapper.vm.filters = [filter];
1309
+ wrapper.vm.updateFiltersFromProps([{ ...filter, selectOptions: [] }]);
1310
+ expect(wrapper.vm.filters).toStrictEqual([
1311
+ { ...filter, selectOptions: [], value: null },
1312
+ ]);
1313
+ });
1314
+
1315
+ test('should not change filter other than options', () => {
1316
+ const wrapper = factory();
1317
+ const filter: Filter = {
1318
+ key: 'filter0',
1319
+ label: 'Zéro',
1320
+ type: 'select',
1321
+ selectOptions: [{ label: 'option1', value: '1' }],
1322
+ };
1323
+
1324
+ wrapper.vm.filters = [filter];
1325
+ wrapper.vm.updateFiltersFromProps([
1326
+ {
1327
+ key: 'filter0',
1328
+ label: 'new label',
1329
+ type: 'input',
1330
+ selectOptions: [{ label: 'option1', value: '1' }],
1331
+ },
1332
+ ]);
1333
+ expect(wrapper.vm.filters).toStrictEqual([filter]);
1334
+ });
1335
+ test('should keep value if is in new options', () => {
1336
+ const wrapper = factory();
1337
+ const filter: Filter = {
1338
+ key: 'filter0',
1339
+ label: 'Zéro',
1340
+ type: 'select',
1341
+ selectOptions: [
1342
+ { label: 'option1', value: '1' },
1343
+ { label: 'option2', value: '2' },
1344
+ ],
1345
+ };
1346
+
1347
+ wrapper.vm.filters = [filter];
1348
+ wrapper.vm.updateFiltersFromProps([
1349
+ {
1350
+ key: 'filter0',
1351
+ label: 'Zéro',
1352
+ type: 'select',
1353
+ selectOptions: [
1354
+ { label: 'option1', value: '1' },
1355
+ { label: 'option3', value: '3' },
1356
+ ],
1357
+ },
1358
+ ]);
1359
+ expect(wrapper.vm.filters).toStrictEqual([
1360
+ {
1361
+ ...filter,
1362
+ selectOptions: [
1363
+ { label: 'option1', value: '1' },
1364
+ { label: 'option3', value: '3' },
1365
+ ],
1366
+ },
1367
+ ]);
1368
+ });
1369
+ });
1295
1370
  });
1296
1371
  });
@@ -183,6 +183,7 @@ export const useSearch = (
183
183
  reflectSearchToUserPref(search.value);
184
184
  }
185
185
  });
186
+
186
187
  watch(
187
188
  () => filters,
188
189
  () => {
@@ -233,19 +234,23 @@ export const useSearch = (
233
234
  });
234
235
  };
235
236
 
237
+ const resetFilterValue = (filter: Filter) => {
238
+ let resetFilter = { ...filter };
239
+ const valueKeys = ['value', 'valueFrom', 'valueTo'];
240
+ valueKeys.forEach((key) => {
241
+ if (
242
+ resetFilter[key as keyof Filter] !== null &&
243
+ resetFilter[key as keyof Filter] !== undefined
244
+ ) {
245
+ resetFilter[key as keyof Filter] = null;
246
+ }
247
+ });
248
+ return resetFilter;
249
+ };
250
+
236
251
  const resetFilters = () => {
237
252
  filters.value = filters.value.map((filter) => {
238
- let resetFilter = { ...filter };
239
- const valueKeys = ['value', 'valueFrom', 'valueTo'];
240
- valueKeys.forEach((key) => {
241
- if (
242
- resetFilter[key as keyof Filter] !== null &&
243
- resetFilter[key as keyof Filter] !== undefined
244
- ) {
245
- resetFilter[key as keyof Filter] = null;
246
- }
247
- });
248
- return resetFilter;
253
+ return resetFilterValue(filter);
249
254
  });
250
255
  };
251
256
 
@@ -264,6 +269,43 @@ export const useSearch = (
264
269
  }
265
270
  };
266
271
 
272
+ const updateFiltersFromProps = (updatedFilters: Filter[]) => {
273
+ filters.value = filters.value.map((filter) => {
274
+ const updatedFilter = updatedFilters.find((f) => f.key === filter.key);
275
+
276
+ if (updatedFilter) {
277
+ let mergedFilter = { ...filter };
278
+
279
+ if (updatedFilter.autocompleteOptions)
280
+ mergedFilter.autocompleteOptions = updatedFilter.autocompleteOptions;
281
+ if (updatedFilter.selectOptions)
282
+ mergedFilter.selectOptions = updatedFilter.selectOptions;
283
+
284
+ const value = filter.value || filter.valueFrom || filter.valueTo;
285
+
286
+ const isValueValidSelectOption =
287
+ updatedFilter.type === 'select' &&
288
+ updatedFilter.selectOptions?.find((option) => option.value === value);
289
+
290
+ const isValueValidAutocompleteOption =
291
+ updatedFilter.type === 'autocomplete' &&
292
+ updatedFilter.autocompleteOptions?.find((option) => option === value);
293
+
294
+ if (
295
+ value &&
296
+ !isValueValidSelectOption &&
297
+ !isValueValidAutocompleteOption
298
+ ) {
299
+ mergedFilter = resetFilterValue(mergedFilter);
300
+ }
301
+
302
+ return mergedFilter;
303
+ } else {
304
+ return filter;
305
+ }
306
+ });
307
+ };
308
+
267
309
  return {
268
310
  search,
269
311
  reflect,
@@ -277,6 +319,7 @@ export const useSearch = (
277
319
  resetFilters,
278
320
  selectSavedFilter,
279
321
  resetAllFilters,
322
+ updateFiltersFromProps,
280
323
  };
281
324
  };
282
325
 
@@ -24,17 +24,17 @@
24
24
  </span>
25
25
  </div>
26
26
 
27
- <div v-if="captions?.length" class="field__captions">
27
+ <div v-if="captions?.length || errors?.length" class="field__captions">
28
28
  <div
29
+ v-if="captions?.length"
29
30
  v-for="caption in captions"
30
31
  :key="getCaptionIdentifier(caption)"
31
32
  class="information field__caption"
32
33
  >
33
34
  <BmsCaption :caption="caption" />
34
35
  </div>
35
- </div>
36
- <div v-if="errors?.length" class="field__errors">
37
36
  <div
37
+ v-if="errors?.length"
38
38
  v-for="error in computedErrors"
39
39
  :key="error.label"
40
40
  class="field__error"
@@ -186,7 +186,9 @@ const getCaptionIdentifier = (caption: string | Caption): string => {
186
186
  --field-padding: 0.5em;
187
187
  --field-margin: 0;
188
188
  --field-label-font-weight: normal;
189
- // color: var(--bms-grey-75);
189
+ .field__captions {
190
+ margin-top: 0.5rem;
191
+ }
190
192
  }
191
193
 
192
194
  &.is-error {
@@ -204,7 +206,7 @@ const getCaptionIdentifier = (caption: string | Caption): string => {
204
206
  margin: 0;
205
207
  background: var(--bms-white);
206
208
  width: 100%;
207
- z-index: 100;
209
+ z-index: var(--bms-z-index-tooltip);
208
210
  max-height: 300px;
209
211
  overflow-y: auto;
210
212
 
@@ -27,15 +27,6 @@ Default.args = {
27
27
  })),
28
28
  };
29
29
 
30
- export const WithSelectedItem = Template.bind({});
31
- WithSelectedItem.args = {
32
- currentSelectedItemIndex: 1,
33
- options: ['toto', 'titi', 'tutu', 'tirlitititututatoooo'].map((i) => ({
34
- label: i,
35
- value: i,
36
- })),
37
- };
38
-
39
30
  export const CanAddNewOption = Template.bind({});
40
31
  CanAddNewOption.args = {
41
32
  options: ['toto', 'titi', 'tutu', 'tirlitititututatoooo'].map((i) => ({
@@ -1,29 +1,21 @@
1
1
  <template>
2
- <ul
3
- class="options-list"
4
- data-testid="select-options"
5
- @keydown.up="keyUp"
6
- @keydown.down="keyDown"
7
- @keydown.enter="keyEnter"
8
- >
2
+ <ul class="options-list" data-testid="select-options">
9
3
  <li
10
4
  v-for="(option, index) in options"
11
5
  :key="index"
12
6
  :data-testid="option.value"
13
7
  :class="{
8
+ 'datalist-option': true,
14
9
  selected: index === currentSelectedItemIndex,
15
10
  small,
16
11
  }"
17
- @click.prevent="onClick(option)"
12
+ @click.stop="onClick(option)"
18
13
  >
19
14
  <slot name="option" :option="option">
20
15
  {{ option.label === null ? 'N/A' : option.label }}
21
16
  </slot>
22
17
  </li>
23
- <li
24
- v-if="displayNewOption"
25
- @click.prevent="$emits('addNewOption', newOption)"
26
- >
18
+ <li v-if="displayNewOption" @click.stop="$emits('addNewOption', newOption)">
27
19
  <slot name="new-option"> {{ newOption }} (nouvelle option) </slot>
28
20
  </li>
29
21
  </ul>
@@ -31,7 +23,7 @@
31
23
 
32
24
  <script setup lang="ts">
33
25
  import { InputOption } from '@/models';
34
- import { computed, onMounted, ref } from 'vue';
26
+ import { computed, onMounted, onUnmounted, ref } from 'vue';
35
27
 
36
28
  export interface Props {
37
29
  options: InputOption[];
@@ -52,17 +44,24 @@ const currentSelectedItemIndex = ref<number>(-1);
52
44
  const $emits = defineEmits<{
53
45
  select: [option: any];
54
46
  addNewOption: [option: string];
47
+ blur: [];
55
48
  }>();
56
49
 
57
50
  const keyDownEventListener = (ev: KeyboardEvent) => {
58
51
  if (props.isInputFocused) {
59
52
  switch (ev.key) {
60
53
  case 'ArrowDown':
54
+ ev.preventDefault();
61
55
  return keyDown();
62
56
  case 'ArrowUp':
57
+ ev.preventDefault();
63
58
  return keyUp();
64
59
  case 'Enter':
60
+ ev.preventDefault();
65
61
  return keyEnter();
62
+ case 'Escape':
63
+ ev.preventDefault();
64
+ return keyEscape();
66
65
  default:
67
66
  return;
68
67
  }
@@ -96,6 +95,10 @@ const keyEnter = () => {
96
95
  }
97
96
  };
98
97
 
98
+ const keyEscape = () => {
99
+ $emits('blur');
100
+ };
101
+
99
102
  const onClick = (option: { label: string; value: any }) => {
100
103
  $emits('select', option);
101
104
  };
@@ -5,8 +5,8 @@ export interface FieldComponentProps {
5
5
  required?: boolean;
6
6
  optional?: boolean;
7
7
  helperText?: string;
8
- errors?: string[] | Caption[];
9
- captions?: string[] | Caption[];
8
+ errors?: (string | Caption)[];
9
+ captions?: (string | Caption)[];
10
10
  disabled?: boolean;
11
11
  small?: boolean;
12
12
  }
@@ -100,7 +100,7 @@ const closeDetails = () => {
100
100
  top: var(--bms-notifications-top);
101
101
  width: 100%;
102
102
  max-width: var(--bms-notifications-width);
103
- z-index: 20;
103
+ z-index: var(--bms-z-index-fixed);
104
104
 
105
105
  &__item {
106
106
  &:not(:first-child) {
@@ -11,7 +11,6 @@
11
11
  :can-add-new-option="true"
12
12
  @add-new-option="onAddNewOption"
13
13
  />
14
-
15
14
  Valeur: {{ inputValueIcon }}
16
15
  <BmsAutocomplete
17
16
  label="Autocomplete avec icones"
@@ -26,6 +25,20 @@
26
25
  :options="optionsText"
27
26
  v-model="inputText"
28
27
  />
28
+
29
+ <BmsSelect
30
+ label="Select"
31
+ @blur="console.log('blur')"
32
+ v-model="select"
33
+ :options="optionsLabelValue"
34
+ />
35
+
36
+ <BmsMultiSelect
37
+ label="Multi-select"
38
+ v-model="multiSelect"
39
+ :options="optionsLabelValue"
40
+ />
41
+ <br />
29
42
  </template>
30
43
 
31
44
  <script setup lang="ts">
@@ -34,6 +47,14 @@ import { Heart, Cat } from 'lucide-vue-next';
34
47
  import { range } from 'lodash';
35
48
  import { ref } from 'vue';
36
49
  import BmsButton from '@/components/button/BmsButton.vue';
50
+ import BmsSelect from '@/components/form/BmsSelect.vue';
51
+ import BmsMultiSelect from '@/components/form/BmsMultiSelect.vue';
52
+ import FieldDatalist from '@/plugins/field/FieldDatalist.vue';
53
+ import RawAutocomplete from '@/components/form/RawAutocomplete.vue';
54
+ import BmsInputText from '@/components/form/BmsInputText.vue';
55
+
56
+ const select = ref('');
57
+ const multiSelect = ref([]);
37
58
 
38
59
  const optionsLabelValue = ref(
39
60
  range(0, 30).map((i) =>
@@ -1,4 +1,5 @@
1
1
  <template>
2
+ {{ filters }}
2
3
  <bms-server-table
3
4
  v-model:selectedItems="selectedItems"
4
5
  v-model:selectMode="selectMode"
@@ -13,6 +14,8 @@
13
14
  :total="totalItems"
14
15
  @saveFilter="onSaveFilter"
15
16
  @deleteSavedFilter="onDeleteSavedFilter"
17
+ @filterInput="onFilterInput"
18
+ @filterChange="onFilterChange"
16
19
  >
17
20
  <template #default="{ row }: { row: any }">
18
21
  <td>
@@ -40,7 +43,7 @@
40
43
  <script lang="ts" setup>
41
44
  import { Filter, SavedFilter, SelectMode } from '@/models';
42
45
  import axios from 'axios';
43
- import { Ref, ref } from 'vue';
46
+ import { computed, Ref, ref } from 'vue';
44
47
  import { isEmptyStringOrNotDefined } from '@/helpers';
45
48
 
46
49
  const serverHeaders = [
@@ -49,7 +52,27 @@ const serverHeaders = [
49
52
  { label: 'Type', key: 'type' },
50
53
  ];
51
54
 
52
- const filters = [
55
+ const typeOptions = ref([
56
+ 'Grass',
57
+ 'Poison',
58
+ 'Fire',
59
+ 'Flying',
60
+ 'Water',
61
+ 'Bug',
62
+ 'Normal',
63
+ 'Electric',
64
+ 'Ground',
65
+ 'Fairy',
66
+ 'Fighting',
67
+ 'Psychic',
68
+ 'Rock',
69
+ 'Steel',
70
+ 'Ice',
71
+ 'Ghost',
72
+ 'Dragon',
73
+ ]);
74
+
75
+ const filters = computed(() => [
53
76
  {
54
77
  label: 'Name',
55
78
  key: 'name',
@@ -65,27 +88,9 @@ const filters = [
65
88
  label: 'Type',
66
89
  key: 'type',
67
90
  type: 'autocomplete',
68
- autocompleteOptions: [
69
- 'Grass',
70
- 'Poison',
71
- 'Fire',
72
- 'Flying',
73
- 'Water',
74
- 'Bug',
75
- 'Normal',
76
- 'Electric',
77
- 'Ground',
78
- 'Fairy',
79
- 'Fighting',
80
- 'Psychic',
81
- 'Rock',
82
- 'Steel',
83
- 'Ice',
84
- 'Ghost',
85
- 'Dragon',
86
- ],
91
+ autocompleteOptions: typeOptions.value,
87
92
  },
88
- ];
93
+ ]);
89
94
 
90
95
  const savedFilters: Ref<SavedFilter[]> = ref<SavedFilter[]>([]);
91
96
  const selectedItems = ref<any[]>([]);
@@ -102,6 +107,32 @@ const onDeleteSavedFilter = (savedFilter: SavedFilter) => {
102
107
  );
103
108
  };
104
109
 
110
+ const onFilterInput = ({
111
+ filterKey,
112
+ e,
113
+ }: {
114
+ filterKey: string;
115
+ e: InputEvent;
116
+ }) => {
117
+ typeOptions.value = [];
118
+ console.log(
119
+ `user filtered key ${filterKey} with val ${(e.target as HTMLInputElement)?.value}`,
120
+ );
121
+ };
122
+
123
+ const onFilterChange = ({
124
+ filterKey,
125
+ e,
126
+ }: {
127
+ filterKey: string;
128
+ e: InputEvent;
129
+ }) => {
130
+ typeOptions.value = [];
131
+ console.log(
132
+ `user filtered key ${filterKey} changed with val ${(e.target as HTMLInputElement)?.value}`,
133
+ );
134
+ };
135
+
105
136
  const customFetchData = async (
106
137
  params: any,
107
138
  abortController: AbortController,