@ouestfrance/sipa-bms-ui 8.15.1 → 8.17.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 (35) hide show
  1. package/dist/components/layout/BmsFloatingWindow.vue.d.ts +19 -0
  2. package/dist/components/layout/BmsSplitWindow.vue.d.ts +35 -0
  3. package/dist/components/table/BmsTable.vue.d.ts +3 -1
  4. package/dist/components/table/UiBmsTable.vue.d.ts +1 -1
  5. package/dist/helpers/table.helper.d.ts +1 -0
  6. package/dist/index.d.ts +3 -1
  7. package/dist/mockServiceWorker.js +1 -1
  8. package/dist/models/table.model.d.ts +2 -1
  9. package/dist/sipa-bms-ui.css +168 -88
  10. package/dist/sipa-bms-ui.es.js +5086 -4115
  11. package/dist/sipa-bms-ui.es.js.map +1 -1
  12. package/dist/sipa-bms-ui.umd.js +5094 -4120
  13. package/dist/sipa-bms-ui.umd.js.map +1 -1
  14. package/package.json +19 -19
  15. package/src/components/form/BmsMultiSelect.vue +5 -1
  16. package/src/components/form/BmsServerAutocomplete.vue +13 -3
  17. package/src/components/layout/BmsFloatingWindow.stories.js +109 -0
  18. package/src/components/layout/BmsFloatingWindow.vue +83 -0
  19. package/src/components/layout/BmsModal.vue +1 -1
  20. package/src/components/layout/BmsSplitWindow.stories.js +155 -0
  21. package/src/components/layout/BmsSplitWindow.vue +290 -0
  22. package/src/components/table/BmsTable.stories.js +47 -0
  23. package/src/components/table/BmsTable.vue +22 -3
  24. package/src/components/table/UiBmsTable.spec.ts +47 -3
  25. package/src/components/table/UiBmsTable.stories.js +43 -0
  26. package/src/components/table/UiBmsTable.vue +51 -91
  27. package/src/components/table/UiBmsTableRow.vue +18 -3
  28. package/src/documentation/principles.mdx +73 -7
  29. package/src/helpers/table.helper.ts +19 -0
  30. package/src/index.ts +6 -0
  31. package/src/models/table.model.ts +1 -0
  32. package/src/showroom/pages/autocomplete.vue +2 -2
  33. package/src/showroom/pages/server-table.vue +2 -7
  34. package/src/showroom/pages/table.vue +3 -0
  35. package/src/showroom/server.js +19 -11
@@ -21,12 +21,12 @@ import BmsLoader from '../feedback/BmsLoader.vue';
21
21
  import { ChevronDown, ChevronsUpDown, ChevronUp } from 'lucide-vue-next';
22
22
  import UiBmsInputCheckbox from '../form/UiBmsInputCheckbox.vue';
23
23
  import BmsAlert from '../feedback/BmsAlert.vue';
24
- import { enforceActionsColumnHeader } from '@/helpers';
24
+ import { enforceActionsColumnHeader, getHeaderClasses } from '@/helpers';
25
25
  import UiBmsTableRow from './UiBmsTableRow.vue';
26
26
 
27
27
  interface UiBmsTableProps {
28
28
  headers: TableHeader[];
29
- items: unknown[];
29
+ items: any[];
30
30
  mode?: 'normal' | 'dense';
31
31
  loading?: boolean;
32
32
  hasFilters?: boolean;
@@ -62,37 +62,31 @@ const emits = defineEmits<{
62
62
  clearSelection: [];
63
63
  }>();
64
64
 
65
+ // Pagination
65
66
  const pagination = ref<HTMLInputElement | null>(null);
66
- const isHeaderStuck = ref<boolean>(false);
67
- const thead = ref<HTMLHeadElement | null>(null);
67
+ const isFocusOnPagination = () =>
68
+ pagination.value?.contains(document.activeElement);
68
69
 
69
- const filteredHeaders = computed(() => {
70
- return enforceActionsColumnHeader(props.headers);
71
- });
70
+ watch(
71
+ () => props.items,
72
+ async function keepFocusOnPaginationWhenUsed(newVal, oldVal) {
73
+ if (oldVal.length > 0 && newVal.length > 0 && isFocusOnPagination()) {
74
+ await nextTick();
75
+ pagination.value?.focus();
76
+ }
77
+ },
78
+ { deep: true },
79
+ );
80
+
81
+ // Headers style
82
+ const filteredHeaders = computed(() =>
83
+ enforceActionsColumnHeader(props.headers),
84
+ );
72
85
 
73
86
  const tableClass = computed(
74
87
  () => `bms-table__table bms-table__table--${props.mode}`,
75
88
  );
76
89
 
77
- const getAlignClass = (header: TableHeader) => {
78
- const align = !header.align ? 'start' : header.align;
79
- return `u-text-align-${align}`;
80
- };
81
-
82
- const getHeaderClasses = (header: TableHeader): string[] => {
83
- const classes = [getAlignClass(header), 'bms-table__header-cell'];
84
- if (header.class) {
85
- classes.push(header.class);
86
- }
87
- if (header.sortable) {
88
- classes.push('sortable');
89
- }
90
- if (props.sort.key === header.key) {
91
- classes.push('sorted');
92
- }
93
- return classes;
94
- };
95
-
96
90
  const getSortComponent = (header: TableHeader): Component => {
97
91
  if (!props.sort.key || header.key !== props.sort.key) {
98
92
  return ChevronsUpDown;
@@ -107,48 +101,23 @@ const getSortComponent = (header: TableHeader): Component => {
107
101
  }
108
102
  };
109
103
 
110
- const isFocusOnPagination = () => {
111
- return pagination.value?.contains(document.activeElement);
112
- };
113
-
114
- watch(
115
- () => props.items,
116
- async (newVal, oldVal) => {
117
- if (oldVal.length > 0 && newVal.length > 0 && isFocusOnPagination()) {
118
- await nextTick();
119
- pagination.value?.focus();
120
- }
121
- },
122
- { deep: true },
123
- );
124
-
125
- onscroll = () => {
126
- if (thead.value) {
127
- const { top: theadTop } = thead.value.getBoundingClientRect();
128
- const headers = document.getElementsByTagName('header');
129
- if (headers.length > 0) {
130
- const header = headers[0];
131
- const { height: headerHeight } = header.getBoundingClientRect();
132
- isHeaderStuck.value = headerHeight === theadTop;
133
- }
134
- }
135
- };
136
-
137
- const isItemSelected = (item: unknown): boolean => {
138
- return (
139
- props.selectMode === SelectMode.ALL ||
140
- !!selectedItems.value.find((it) => _isEqual(item, it))
141
- );
142
- };
104
+ // Selection
105
+ const isItemSelected = (item: unknown): boolean =>
106
+ props.selectMode === SelectMode.ALL ||
107
+ !!selectedItems.value.find((it) => _isEqual(item, it));
143
108
 
144
109
  const onItemSelect = (item: unknown) => {
145
- if (isItemSelected(item)) {
146
- selectedItems.value = selectedItems.value.filter(
147
- (it) => !_isEqual(item, it),
148
- );
149
- areAllCurrentItemsSelected.value = false;
110
+ if (props.selectMode === SelectMode.SINGLE) {
111
+ selectedItems.value = [item];
150
112
  } else {
151
- selectedItems.value.push(item);
113
+ if (isItemSelected(item)) {
114
+ selectedItems.value = selectedItems.value.filter(
115
+ (it) => !_isEqual(item, it),
116
+ );
117
+ areAllCurrentItemsSelected.value = false;
118
+ } else {
119
+ selectedItems.value.push(item);
120
+ }
152
121
  }
153
122
  };
154
123
 
@@ -165,26 +134,27 @@ const onToggleSelectAllCurrentItems = () => {
165
134
  }
166
135
 
167
136
  // If we have a selection spanning across more than the current page
168
- if (selectedItems.value.length > props.items.length) {
137
+ if (selectedItems.value.length > props.totalSize) {
169
138
  selectedItems.value = [] as unknown[];
170
139
  } else {
171
- // If all the current page is selected
140
+ // If only some are selected
172
141
  if (!areAllCurrentItemsSelected.value) {
173
142
  props.items.forEach((item) => {
174
143
  if (!isItemSelected(item)) {
175
144
  selectedItems.value.push(item);
176
145
  }
146
+ if (item?.childElement && !isItemSelected(item?.childElement)) {
147
+ selectedItems.value.push(item.childElement);
148
+ }
177
149
  });
178
150
  } else {
179
- // If nothing selected
180
- selectedItems.value = selectedItems.value.filter(
181
- (selectedItem) =>
182
- !props.items.find((item) => _isEqual(item, selectedItem)),
183
- );
151
+ // If all the current page is selected
152
+ selectedItems.value = [];
184
153
  }
185
154
  }
186
155
  };
187
156
 
157
+ // Blob animation
188
158
  const blob = ref<HTMLDivElement | null>(null);
189
159
  const mainComponent = ref<HTMLDivElement | null>(null);
190
160
 
@@ -220,6 +190,7 @@ const onMouseMove = (e: MouseEvent) => {
220
190
  };
221
191
 
222
192
  window.addEventListener('mousemove', onMouseMove);
193
+
223
194
  watch(
224
195
  () => props.items.length,
225
196
  () => {
@@ -282,7 +253,9 @@ onMounted(() => {
282
253
  <span
283
254
  class="select-mode-all"
284
255
  @click="selectAll"
285
- v-if="totalSize < maxSelectedSize"
256
+ v-if="
257
+ totalSize < maxSelectedSize && selectMode !== SelectMode.SINGLE
258
+ "
286
259
  >
287
260
  Sélectionner la totalité des {{ totalSize }} éléments
288
261
  </span>
@@ -305,14 +278,11 @@ onMounted(() => {
305
278
  :class="tableClass"
306
279
  ref="mainComponent"
307
280
  >
308
- <thead
309
- ref="thead"
310
- class="bms-table__header"
311
- :class="{ stuck: isHeaderStuck }"
312
- >
281
+ <thead ref="thead" class="bms-table__header">
313
282
  <tr class="bms-table__headers bms-table__row">
314
283
  <th v-if="selectable">
315
284
  <UiBmsInputCheckbox
285
+ v-if="selectMode !== SelectMode.SINGLE"
316
286
  name="select-all"
317
287
  :disabled="items.length === 0 || selectableDisabled"
318
288
  @update:model-value="onToggleSelectAllCurrentItems"
@@ -324,7 +294,7 @@ onMounted(() => {
324
294
  :style="{
325
295
  '--table-cell-width': header?.width || undefined,
326
296
  }"
327
- :class="getHeaderClasses(header)"
297
+ :class="getHeaderClasses(header, sort)"
328
298
  :key="header.label"
329
299
  @click="emits('clickHeader', header)"
330
300
  >
@@ -360,8 +330,7 @@ onMounted(() => {
360
330
  <slot name="default" :row="row"></slot>
361
331
  </template>
362
332
  </UiBmsTableRow>
363
- <!-- FIXME typing -->
364
- <template v-if="(item as any)?.childElement">
333
+ <template v-if="item?.childElement">
365
334
  <slot name="child-element">
366
335
  <UiBmsTableRow
367
336
  is-child-element
@@ -371,6 +340,7 @@ onMounted(() => {
371
340
  :headers="filteredHeaders"
372
341
  :select-mode="selectMode"
373
342
  :selectable-disabled="selectableDisabled"
343
+ @select="onItemSelect"
374
344
  >
375
345
  <template
376
346
  v-for="cell in headers"
@@ -579,16 +549,6 @@ onMounted(() => {
579
549
  border-top-left-radius: var(--table-cell-radius);
580
550
  }
581
551
 
582
- .stuck {
583
- th:first-child {
584
- border-top-left-radius: 0;
585
- }
586
-
587
- th:last-child {
588
- border-top-right-radius: 0;
589
- }
590
- }
591
-
592
552
  th:last-child {
593
553
  border-top-right-radius: var(--table-cell-radius);
594
554
  }
@@ -2,7 +2,7 @@
2
2
  <tr
3
3
  class="bms-table__row"
4
4
  :class="{
5
- 'bms-table__row--selected': isItemSelected(item),
5
+ 'bms-table__row--selected': isItemSelected(currentItem),
6
6
  'bms-table__row--disabled': isChildElement,
7
7
  'bms-table__row--dense': dense,
8
8
  }"
@@ -13,11 +13,20 @@
13
13
  tooltip-text="Vous ne pouvez pas désélectionner un élément unitairement si vous avez choisi de sélectionner la totalité des éléments"
14
14
  :activated="selectMode === SelectMode.ALL"
15
15
  >
16
+ <BmsInputRadio
17
+ v-if="selectMode === SelectMode.SINGLE"
18
+ :name="uuid()"
19
+ :disabled="selectableDisabled"
20
+ :value="currentItem"
21
+ :model-value="isItemSelected(currentItem) ? currentItem : null"
22
+ @update:model-value="emits('select', currentItem)"
23
+ />
16
24
  <UiBmsInputCheckbox
25
+ v-else
17
26
  :name="uuid()"
18
27
  :disabled="selectMode === SelectMode.ALL || selectableDisabled"
19
- :model-value="isItemSelected(item)"
20
- @update:model-value="emits('select', item)"
28
+ :model-value="isItemSelected(currentItem)"
29
+ @update:model-value="emits('select', currentItem)"
21
30
  />
22
31
  </BmsTooltip>
23
32
  </td>
@@ -69,6 +78,8 @@ import UiBmsInputCheckbox from '../form/UiBmsInputCheckbox.vue';
69
78
  import BmsTooltip from '../feedback/BmsTooltip.vue';
70
79
  import { CornerDownRight } from 'lucide-vue-next';
71
80
  import UiBmsTableCell from './UiBmsTableCell.vue';
81
+ import BmsInputRadio from '../form/BmsInputRadio.vue';
82
+ import { computed } from 'vue';
72
83
 
73
84
  interface Props {
74
85
  item: any;
@@ -87,6 +98,10 @@ const props = withDefaults(defineProps<Props>(), {
87
98
 
88
99
  const emits = defineEmits<{ select: [item: any] }>();
89
100
 
101
+ const currentItem = computed(() =>
102
+ props.isChildElement ? props.item.childElement : props.item,
103
+ );
104
+
90
105
  const isItemSelected = (item: unknown): boolean => {
91
106
  return (
92
107
  props.selectMode === SelectMode.ALL ||
@@ -1,10 +1,4 @@
1
- import {
2
- Canvas,
3
- Meta,
4
- Story,
5
- Stories,
6
- Controls,
7
- } from '@storybook/addon-docs/blocks';
1
+ import { Meta } from '@storybook/addon-docs/blocks';
8
2
 
9
3
  ![](./CoverBmsUI.png)
10
4
 
@@ -21,3 +15,75 @@ bms UI focuses on the essentials, we concentrate on what is useful for interface
21
15
  ## Design System by constraint
22
16
 
23
17
  A constraint-based design system is designed to offer a consistent user experience across all products that use it. By limiting possible interpretations, this type of design system provides a clear and consistent logic that facilitates understanding and use of the products. Constraints can be applied to visual elements such as colors, typography, and font sizes, as well as interactive elements such as buttons and menus. By using a constraint-based design system, users can interact with products with confidence, knowing that the design elements will be consistent and predictable.
18
+
19
+ ## 📖 Documentation of the **bms UI** Design System
20
+
21
+ > **Mission** – Provide a **single Design System** dedicated to the Sipa group’s Back‑Office tools, limiting the use of the Vue framework and offering a constraint‑driven approach to interface design and construction. Goal: reduce costs, ensure visual and functional consistency, and simplify maintenance.
22
+
23
+ ---
24
+
25
+ ### 1️⃣ Context & Objectives
26
+
27
+ - **Who?**
28
+ The bms UI Design System is actually maintained by the frontend team of **bms**.
29
+
30
+ - **Why?**
31
+ - Uniform the look‑and‑feel of internal products and applications.
32
+ - Limit Vue code sprawl and avoid ad‑hoc solutions.
33
+ - Speed up development with reusable, tested components.
34
+
35
+ - **Target audience**
36
+ Front‑end developers, designers, QA engineers, project managers, and anyone involved in creating or maintaining Back‑Office interfaces.
37
+
38
+ ### 2️⃣ Core Principles
39
+
40
+ #### 2.1 Focused – Essentials First
41
+
42
+ > _“We concentrate on what truly matters for interfaces, nothing superfluous.”_
43
+
44
+ - **Functional minimalism** – Each component must solve a clearly identified need.
45
+ - **Dependency pruning** – Keep external imports to a minimum to reduce bundle size.
46
+ - **Concise documentation** – Every component includes essential props, available slots, and a usage example.
47
+
48
+ #### 2.2 Design System by Constraint – Constraint as a Cohesion Lever
49
+
50
+ > _“By limiting possible interpretations, we create a clear and predictable logic.”_
51
+
52
+ | Domain | Applied Constraints |
53
+ | ---------------- | ---------------------------------------------------------- |
54
+ | **Colors** | Restricted palette – no free‑form colors. |
55
+ | **Typography** | One font families, predefined sizes. |
56
+ | **Spacing** | Margin/padding scale based on a 8 px step. |
57
+ | **Interactions** | Standardised states (default, hover, focus, disabled). |
58
+ | **Behavior** | Uniform Vue API (`v-model` where applicable, named slots). |
59
+
60
+ These constraints are **declarative** – they’re baked directly into components (e.g., `mode="danger"` to have a red button), preventing stylistic drift.
61
+
62
+ ### 3️⃣ Project Architecture
63
+
64
+ - **Single export** – `import BmsButton from '../components/button/BmsButton.vue';`
65
+ - **Integrated Storybook** – Each component has a `*.stories.js` file showcasing the UI and the props & slots for each component.```
66
+ - **Typescript components** - Each component as typed props & events, and the relevant types are exported by the library (e.g. TableHeader, Caption, etc.)
67
+
68
+ ### 4️⃣ Usage Guide
69
+
70
+ #### 4.1 Installation
71
+
72
+ Gitlab documentation https://gitlab.ouest-france.fr/sipa-ouest-france/platform/platform-library-vuejs-bms#installation
73
+
74
+ ### 5️⃣ Quick FAQ
75
+
76
+ - **Can I add a custom color?**
77
+ **Answer:** No – all colors must come from the defined palette. If a legitimate need arises, open a **Jira** ticket.
78
+
79
+ - **How do I handle a new breakpoint?**
80
+ **Answer:** There are no breakpoints – bmsUI only provides desktop‑only interfaces.
81
+
82
+ - **Does the design system support dark mode?**
83
+ **Answer:** No – theming is not available at this time.
84
+
85
+ ### 6️⃣ Contact & Support
86
+
87
+ - **Teams**: [#🎨bmsUI](https://teams.microsoft.com/l/channel/19%3Au9dPXr-JjoRoaLat-EyS-QEKit1ZzUwQ7G0VrzvDkTE1%40thread.tacv2/%F0%9F%8E%A8bmsUI?groupId=677fd2f9-de86-4bf9-a00c-71817f033ad3&tenantId=a59e9cc9-4ed4-43c4-9f1e-ca78d44b0072&ngc=true&allowXTenantAccess=)
88
+ - **Issues**: [#Jira] (⚠️ WIP)
89
+ - **Gitlab**: [Gitlab](https://gitlab.ouest-france.fr/sipa-ouest-france/platform/platform-library-vuejs-bms)
@@ -86,3 +86,22 @@ export const enforceActionsColumnHeader = (
86
86
  .filter((h) => !h?.action)
87
87
  .concat(actionsHeaders.length ? actionsHeaders[0] : []);
88
88
  };
89
+
90
+ const getAlignClass = (header: TableHeader) => {
91
+ const align = !header.align ? 'start' : header.align;
92
+ return `u-text-align-${align}`;
93
+ };
94
+
95
+ export const getHeaderClasses = (header: TableHeader, sort: Sort): string[] => {
96
+ const classes = [getAlignClass(header), 'bms-table__header-cell'];
97
+ if (header.class) {
98
+ classes.push(header.class);
99
+ }
100
+ if (header.sortable) {
101
+ classes.push('sortable');
102
+ }
103
+ if (sort.key === header.key) {
104
+ classes.push('sorted');
105
+ }
106
+ return classes;
107
+ };
package/src/index.ts CHANGED
@@ -37,12 +37,14 @@ import BmsTextArea from './components/form/BmsTextArea.vue';
37
37
 
38
38
  import BmsContentPageLayout from './components/layout/BmsContentPageLayout.vue';
39
39
  import BmsCard from './components/layout/BmsCard.vue';
40
+ import BmsFloatingWindow from './components/layout/BmsFloatingWindow.vue';
40
41
  import BmsForm from './components/layout/BmsForm.vue';
41
42
  import BmsHeader from './components/layout/BmsHeader.vue';
42
43
  import BmsHeaderTitle from './components/layout/BmsHeaderTitle.vue';
43
44
  import BmsModal from './components/layout/BmsModal.vue';
44
45
  import BmsOverlay from './components/layout/BmsOverlay.vue';
45
46
  import BmsSection from './components/layout/BmsSection.vue';
47
+ import BmsSplitWindow from './components/layout/BmsSplitWindow.vue';
46
48
  import BmsStep from './components/layout/BmsStep.vue';
47
49
  import BmsStepper from './components/layout/BmsStepper.vue';
48
50
 
@@ -108,12 +110,14 @@ export const createBmsUi = () => ({
108
110
 
109
111
  app.component('BmsContentPageLayout', BmsContentPageLayout);
110
112
  app.component('BmsCard', BmsCard);
113
+ app.component('BmsFloatingWindow', BmsFloatingWindow);
111
114
  app.component('BmsForm', BmsForm);
112
115
  app.component('BmsHeader', BmsHeader);
113
116
  app.component('BmsHeaderTitle', BmsHeaderTitle);
114
117
  app.component('BmsModal', BmsModal);
115
118
  app.component('BmsOverlay', BmsOverlay);
116
119
  app.component('BmsSection', BmsSection);
120
+ app.component('BmsSplitWindow', BmsSplitWindow);
117
121
  app.component('BmsStep', BmsStep);
118
122
  app.component('BmsStepper', BmsStepper);
119
123
 
@@ -185,12 +189,14 @@ export {
185
189
  BmsTextArea,
186
190
  BmsContentPageLayout,
187
191
  BmsCard,
192
+ BmsFloatingWindow,
188
193
  BmsForm,
189
194
  BmsHeader,
190
195
  BmsHeaderTitle,
191
196
  BmsModal,
192
197
  BmsOverlay,
193
198
  BmsSection,
199
+ BmsSplitWindow,
194
200
  BmsStep,
195
201
  BmsStepper,
196
202
  BmsBackButton,
@@ -68,4 +68,5 @@ export interface SavedFilter {
68
68
  export enum SelectMode {
69
69
  ALL = 'all',
70
70
  DEFAULT = 'default',
71
+ SINGLE = 'single',
71
72
  }
@@ -99,10 +99,10 @@ const onAddNewOption = (newOption: string) => {
99
99
  };
100
100
 
101
101
  const autocompleteRequest = (
102
- abortController: AbortController,
102
+ _abortController: AbortController,
103
103
  searchString?: string,
104
104
  ) =>
105
105
  fetch(`http://localhost:3000/pokemon-types?search=${searchString}`).then(
106
- (res) => res.json(),
106
+ (res) => res.json().then((res) => ({ data: res })),
107
107
  );
108
108
  </script>
@@ -30,10 +30,7 @@
30
30
  <div>Nb Selected items: {{ selectedItems.length }}</div>
31
31
  <div>
32
32
  Selected items:
33
- {{
34
- selectMode === SelectMode.ALL &&
35
- selectedItems?.map((i: any) => '#' + i.id + ' : ' + i.name).join(', ')
36
- }}
33
+ {{ selectedItems?.map((i: any) => '#' + i.id + ' : ' + i.name).join(', ') }}
37
34
  </div>
38
35
  </template>
39
36
 
@@ -56,9 +53,7 @@ const pokemonTypeAutocompleteRequest = async (
56
53
  signal: abortController.signal,
57
54
  });
58
55
 
59
- return {
60
- data,
61
- };
56
+ return { data };
62
57
  };
63
58
 
64
59
  const filters: Filter[] = [
@@ -13,6 +13,8 @@
13
13
  help-link="/help-path"
14
14
  activity-link="/activity-path"
15
15
  v-model:selectedItems="selectedItems"
16
+ selectable
17
+ :select-mode="'single'"
16
18
  @saveFilter="onSaveFilter"
17
19
  @deleteSavedFilter="onDeleteSavedFilter"
18
20
  @filterInput="onFilterInput"
@@ -58,6 +60,7 @@ import {
58
60
  Filter,
59
61
  InputType,
60
62
  SavedFilter,
63
+ SelectMode,
61
64
  SortValue,
62
65
  StatusType,
63
66
  } from '@/models';
@@ -9,17 +9,25 @@ app.use(cors());
9
9
  const port = 3000;
10
10
 
11
11
  app.get('/pokemon-types', (req, res) => {
12
- let data = pokemons.map((pokemon) => ({
13
- label: pokemon.name,
14
- value: pokemon.name,
15
- }));
16
- if (req.query.search) {
17
- data = data.filter((pokemon) =>
18
- pokemon.label.toLowerCase().includes(req.query.search.toLowerCase()),
19
- );
20
- }
21
-
22
- res.send({ data });
12
+ res.send([
13
+ { label: 'Grass', value: 'Grass' },
14
+ { label: 'Poison', value: 'Poison' },
15
+ { label: 'Fire', value: 'Fire' },
16
+ { label: 'Flying', value: 'Flying' },
17
+ { label: 'Water', value: 'Water' },
18
+ { label: 'Bug', value: 'Bug' },
19
+ { label: 'Normal', value: 'Normal' },
20
+ { label: 'Electric', value: 'Electric' },
21
+ { label: 'Ground', value: 'Ground' },
22
+ { label: 'Fairy', value: 'Fairy' },
23
+ { label: 'Fighting', value: 'Fighting' },
24
+ { label: 'Psychic', value: 'Psychic' },
25
+ { label: 'Rock', value: 'Rock' },
26
+ { label: 'Steel', value: 'Steel' },
27
+ { label: 'Ice', value: 'Ice' },
28
+ { label: 'Ghost', value: 'Ghost' },
29
+ { label: 'Dragon', value: 'Dragon' },
30
+ ]);
23
31
  });
24
32
 
25
33
  app.get('/pokemons', (req, res) => {