@bexis2/bexis2-core-ui 0.4.9 → 0.4.10

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/README.md CHANGED
@@ -1,7 +1,16 @@
1
- # bexis2-core-ui
2
- ## 0.4.9
3
- - update npm packages
1
+ # bexis-core-ui
2
+ ## 0.4.10
3
+ - Table:
4
+ - Fixes issue with sticky Tables not rendering the filters correctly.
5
+ - Fixes issues related to date picker in Tables with date filters.
6
+ - Updates default Table page sizes to [5, 10, 20, 50, 100].
7
+ - Updates the structure of server-side configuration for Tables.
8
+ - Adds new page size dropdown in Table for to fix contrast issues in the component.
9
+ - Adds showing/hiding Table columns.
4
10
 
11
+ - Facets:
12
+ - Adds Facets component.
13
+
5
14
  ## 0.4.8
6
15
  - page
7
16
  - add notification if api call to backend faild
@@ -0,0 +1,108 @@
1
+ <script>import { getModalStore, Modal, TreeView, TreeViewItem } from "@skeletonlabs/skeleton";
2
+ import ShowMore from "./ShowMore.svelte";
3
+ export let groupSelection = false;
4
+ export let groups;
5
+ export let selected;
6
+ export let selectedGroups = {};
7
+ export let showAll = false;
8
+ export let open = false;
9
+ const modalStore = getModalStore();
10
+ const showMore = (group) => {
11
+ modalStore.trigger({
12
+ type: "component",
13
+ title: `${group}`,
14
+ component: {
15
+ ref: ShowMore,
16
+ props: {
17
+ group,
18
+ handleSave,
19
+ handleCancel,
20
+ selected: selected[group],
21
+ items: groups[group].sort((a, b) => a.value.localeCompare(b.value))
22
+ }
23
+ }
24
+ });
25
+ };
26
+ const handleSave = (group, selectedItems) => {
27
+ selected[group] = selectedItems;
28
+ modalStore.close();
29
+ };
30
+ const handleCancel = () => {
31
+ modalStore.close();
32
+ };
33
+ const sortOptions = () => {
34
+ Object.keys(groups).forEach((group) => {
35
+ groups[group] = [
36
+ ...selected[group].sort((a, b) => {
37
+ if (a.count != void 0 && b.count != void 0) {
38
+ return b.count - a.count;
39
+ }
40
+ return a.value.localeCompare(b.value);
41
+ }),
42
+ ...groups[group].filter((item) => !selected[group].includes(item)).sort((a, b) => {
43
+ if (a.count != void 0 && b.count != void 0) {
44
+ return b.count - a.count;
45
+ }
46
+ return a.value.localeCompare(b.value);
47
+ })
48
+ ];
49
+ });
50
+ };
51
+ $: selected, sortOptions();
52
+ </script>
53
+
54
+ <TreeView selection={groupSelection} multiple={groupSelection} padding="p-1" hover="">
55
+ {#each Object.keys(groups) as group}
56
+ <TreeViewItem
57
+ name="groups"
58
+ value={group}
59
+ {open}
60
+ hyphenOpacity="opacity-0"
61
+ bind:group={selectedGroups}
62
+ bind:checked={selectedGroups[group]}
63
+ >
64
+ <p class="font-semibold">{group}</p>
65
+
66
+ <svelte:fragment slot="children">
67
+ <!-- If more than 5 choices, show the remaining in the Modal -->
68
+ {#if !showAll}
69
+ {#each groups[group].slice(0, 5) as item}
70
+ <TreeViewItem
71
+ bind:group={selected[group]}
72
+ name={group}
73
+ value={item}
74
+ hyphenOpacity="opacity-0"
75
+ spacing="space-x-3"
76
+ selection
77
+ multiple
78
+ >
79
+ <p>{item.value} ({item.count})</p>
80
+ </TreeViewItem>
81
+ {/each}
82
+ <!-- Trigger for the Modal to view all options -->
83
+ {#if groups[group].length > 5}
84
+ <TreeViewItem hyphenOpacity="opacity-0">
85
+ <button class="anchor" on:click={() => showMore(group)}>more</button></TreeViewItem
86
+ >
87
+ {/if}
88
+ {:else}
89
+ {#each groups[group] as item}
90
+ <TreeViewItem
91
+ bind:group={selected[group]}
92
+ name={group}
93
+ value={item}
94
+ hyphenOpacity="opacity-0"
95
+ spacing="space-x-3"
96
+ selection
97
+ multiple
98
+ >
99
+ <p>{item.value} ({item.count})</p>
100
+ </TreeViewItem>
101
+ {/each}
102
+ {/if}
103
+ </svelte:fragment>
104
+ </TreeViewItem>
105
+ {/each}
106
+ </TreeView>
107
+
108
+ <Modal />
@@ -0,0 +1,24 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { FacetGroup } from '../../models/Models';
3
+ declare const __propDef: {
4
+ props: {
5
+ groupSelection?: boolean;
6
+ groups: FacetGroup;
7
+ selected: FacetGroup;
8
+ selectedGroups?: {
9
+ [key: string]: boolean;
10
+ };
11
+ showAll?: boolean;
12
+ open?: boolean;
13
+ };
14
+ events: {
15
+ [evt: string]: CustomEvent<any>;
16
+ };
17
+ slots: {};
18
+ };
19
+ export type FacetsProps = typeof __propDef.props;
20
+ export type FacetsEvents = typeof __propDef.events;
21
+ export type FacetsSlots = typeof __propDef.slots;
22
+ export default class Facets extends SvelteComponent<FacetsProps, FacetsEvents, FacetsSlots> {
23
+ }
24
+ export {};
@@ -0,0 +1,75 @@
1
+ <script>export let group;
2
+ export let items;
3
+ export let selected;
4
+ export let handleSave;
5
+ export let handleCancel;
6
+ let selectedItems = selected;
7
+ const handleCheck = (e, index) => {
8
+ const target = e.target;
9
+ if (target.checked) {
10
+ selectedItems = [...selectedItems, items[index]];
11
+ } else {
12
+ selectedItems = selectedItems.filter((item) => item !== items[index]);
13
+ }
14
+ };
15
+ const selectAll = () => {
16
+ selectedItems = items;
17
+ };
18
+ const selectNone = () => {
19
+ selectedItems = [];
20
+ };
21
+ const onSave = () => {
22
+ handleSave(group, selectedItems);
23
+ };
24
+ const onCancel = () => {
25
+ selectedItems = selected;
26
+ handleCancel();
27
+ };
28
+ const gridClass = (items2) => {
29
+ if (items2.length >= 50) {
30
+ return "grid-cols-5";
31
+ } else if (items2.length >= 30) {
32
+ return "grid-cols-4";
33
+ } else if (items2.length >= 20) {
34
+ return "grid-cols-3";
35
+ }
36
+ return "grid-cols-2";
37
+ };
38
+ </script>
39
+
40
+ <div class="p-5 rounded-md bg-surface-50 dark:bg-surface-800 border-primary-500 border-2">
41
+ <!-- Header -->
42
+ <h2 class="text-xl font-semibold">{group}</h2>
43
+
44
+ <!-- Items -->
45
+ <div
46
+ class="grid {gridClass(
47
+ items
48
+ )} !gap-x-20 gap-y-2 py-10 px-2 max-h-[1000px] overflow-x-auto max-w-6xl"
49
+ >
50
+ {#each items as item, index}
51
+ <label class="flex gap-3 items-center">
52
+ <input
53
+ type="checkbox"
54
+ class="checkbox"
55
+ value={item.value}
56
+ on:click={(e) => handleCheck(e, index)}
57
+ checked={selectedItems.includes(item)}
58
+ />
59
+ <span class="whitespace-nowrap break-before-avoid break-after-avoid">{item.value}</span>
60
+ </label>
61
+ {/each}
62
+ </div>
63
+
64
+ <!-- Footer -->
65
+ <div class="flex w-full justify-between gap-5">
66
+ <div class="flex gap-3">
67
+ <button class="btn btn-sm variant-filled-tertiary" on:click={selectNone}>None</button>
68
+ <button class="btn btn-sm variant-filled-tertiary" on:click={selectAll}>All</button>
69
+ </div>
70
+ <div class="flex gap-3">
71
+ <button class="btn btn-sm variant-filled-primary" on:click={onSave}>Save</button>
72
+ <button class="btn btn-sm variant-filled-secondary" on:click={onCancel}>Cancel</button>
73
+ </div>
74
+ </div>
75
+ </div>
@@ -0,0 +1,21 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { FacetOption } from '../../models/Models';
3
+ declare const __propDef: {
4
+ props: {
5
+ group: string;
6
+ items: FacetOption[];
7
+ selected: FacetOption[];
8
+ handleSave: (group: string, selectedItems: FacetOption[]) => {};
9
+ handleCancel: () => {};
10
+ };
11
+ events: {
12
+ [evt: string]: CustomEvent<any>;
13
+ };
14
+ slots: {};
15
+ };
16
+ export type ShowMoreProps = typeof __propDef.props;
17
+ export type ShowMoreEvents = typeof __propDef.events;
18
+ export type ShowMoreSlots = typeof __propDef.slots;
19
+ export default class ShowMore extends SvelteComponent<ShowMoreProps, ShowMoreEvents, ShowMoreSlots> {
20
+ }
21
+ export {};
@@ -0,0 +1,33 @@
1
+ <script>import { popup } from "@skeletonlabs/skeleton";
2
+ export let columns = [];
3
+ export let tableId;
4
+ const popupCombobox = {
5
+ event: "click",
6
+ target: `${tableId}-columns-menu`,
7
+ placement: "bottom"
8
+ };
9
+ </script>
10
+
11
+ <button
12
+ type="button"
13
+ class="btn btn-sm variant-filled-primary rounded-full order-last"
14
+ use:popup={popupCombobox}>Columns</button
15
+ >
16
+
17
+ <div
18
+ class="bg-white dark:bg-surface-500 p-4 rounded-md shadow-md z-10"
19
+ data-popup="{tableId}-columns-menu"
20
+ >
21
+ {#each columns as column}
22
+ <div class="flex gap-3 items-center">
23
+ <input
24
+ type="checkbox"
25
+ bind:checked={column.visible}
26
+ disabled={columns.filter((c) => c.visible).length === 1 && column.visible}
27
+ />
28
+ <span>{column.label}</span>
29
+ </div>
30
+ {/each}
31
+
32
+ <div class="arrow bg-white dark:bg-surface-500" />
33
+ </div>
@@ -0,0 +1,21 @@
1
+ import { SvelteComponent } from "svelte";
2
+ declare const __propDef: {
3
+ props: {
4
+ columns?: {
5
+ id: string;
6
+ label: string;
7
+ visible: boolean;
8
+ }[];
9
+ tableId: string;
10
+ };
11
+ events: {
12
+ [evt: string]: CustomEvent<any>;
13
+ };
14
+ slots: {};
15
+ };
16
+ export type ColumnsMenuProps = typeof __propDef.props;
17
+ export type ColumnsMenuEvents = typeof __propDef.events;
18
+ export type ColumnsMenuSlots = typeof __propDef.slots;
19
+ export default class ColumnsMenu extends SvelteComponent<ColumnsMenuProps, ColumnsMenuEvents, ColumnsMenuSlots> {
20
+ }
21
+ export {};
@@ -9,7 +9,8 @@ import {
9
9
  addExpandedRows,
10
10
  addColumnFilters,
11
11
  addTableFilter,
12
- addDataExport
12
+ addDataExport,
13
+ addHiddenColumns
13
14
  } from "svelte-headless-table/plugins";
14
15
  import { computePosition, autoUpdate, offset, shift, flip, arrow } from "@floating-ui/dom";
15
16
  import { SlideToggle, storePopup } from "@skeletonlabs/skeleton";
@@ -19,6 +20,7 @@ import TableFilter from "./TableFilter.svelte";
19
20
  import TableFilterServer from "./TableFilterServer.svelte";
20
21
  import TablePagination from "./TablePagination.svelte";
21
22
  import TablePaginationServer from "./TablePaginationServer.svelte";
23
+ import ColumnsMenu from "./ColumnsMenu.svelte";
22
24
  import { columnFilter, searchFilter } from "./filter";
23
25
  import {
24
26
  cellStyle,
@@ -51,27 +53,18 @@ let {
51
53
  // Whether to display the fitToScreen toggle
52
54
  search = true,
53
55
  // Whether to display the search input
54
- pageSizes = [5, 10, 15, 20],
56
+ pageSizes = [5, 10, 20, 50, 100],
55
57
  // Page sizes to display in the pagination component
56
58
  fitToScreen = true,
57
59
  // Whether to fit the table to the screen,
58
60
  exportable = false,
59
61
  // Whether to display the export button and enable export functionality
60
- serverSide = false,
61
- // Whether the table is client or server-side
62
- URL = "",
63
- // URL to fetch data from
64
- token = "",
65
- // Bearer token to authenticate the request
66
- sendModel = new Send(),
67
- // Model to send requests
68
- entityId = 0,
69
- // Entity ID to send with the request
70
- versionId = 0
71
- // Version ID to send with the request,
62
+ server
72
63
  } = config;
73
64
  let searchValue = "";
74
65
  let isFetching = false;
66
+ const serverSide = server !== void 0;
67
+ const { baseUrl, sendModel, entityId, versionId } = server ?? {};
75
68
  const filters = writable({});
76
69
  const dispatch = createEventDispatcher();
77
70
  const actionDispatcher = (obj) => dispatch("action", obj);
@@ -85,6 +78,7 @@ const table = createTable(data, {
85
78
  fn: searchFilter,
86
79
  serverSide
87
80
  }),
81
+ hideColumns: addHiddenColumns(),
88
82
  sort: addSortBy({
89
83
  disableMultiSort: true,
90
84
  serverSide
@@ -109,14 +103,24 @@ Object.keys(allCols).forEach((key) => {
109
103
  $filters = { ...$filters, [key]: {} };
110
104
  });
111
105
  const accessors = Object.keys(allCols);
106
+ const unexcludedColumns = accessors.filter((accessor) => {
107
+ const key = accessor;
108
+ if (columns !== void 0 && key in columns && columns[key].exclude === true) {
109
+ return false;
110
+ }
111
+ return true;
112
+ });
113
+ let shownColumns = unexcludedColumns.map((c) => {
114
+ const key = c;
115
+ const label = key.charAt(0).toUpperCase() + key.slice(1);
116
+ return {
117
+ id: c,
118
+ label: columns && columns[key] && columns[key].header ? columns[key].header : label,
119
+ visible: true
120
+ };
121
+ });
112
122
  const tableColumns = [
113
- ...accessors.filter((accessor) => {
114
- const key = accessor;
115
- if (columns !== void 0 && key in columns && columns[key].exclude === true) {
116
- return false;
117
- }
118
- return true;
119
- }).map((accessor) => {
123
+ ...unexcludedColumns.map((accessor) => {
120
124
  const key = accessor;
121
125
  if (columns !== void 0 && key in columns) {
122
126
  const {
@@ -246,19 +250,20 @@ const { headerRows, pageRows, tableAttrs, tableBodyAttrs, pluginStates } = table
246
250
  const { filterValue } = pluginStates.tableFilter;
247
251
  const { exportedData } = pluginStates.export;
248
252
  const { pageIndex, pageSize } = pluginStates.page;
253
+ const { hiddenColumnIds } = pluginStates.hideColumns;
249
254
  const updateTable = async () => {
255
+ if (!sendModel) throw new Error("Server-side configuration is missing");
250
256
  sendModel.limit = $pageSize;
251
257
  sendModel.offset = $pageSize * $pageIndex;
252
- sendModel.version = versionId;
253
- sendModel.id = entityId;
258
+ sendModel.version = versionId || -1;
259
+ sendModel.id = entityId || -1;
254
260
  sendModel.filter = normalizeFilters($filters);
255
261
  let fetchData;
256
262
  try {
257
263
  isFetching = true;
258
- fetchData = await fetch(URL, {
264
+ fetchData = await fetch(baseUrl || "", {
259
265
  headers: {
260
- "Content-Type": "application/json",
261
- Authorization: `Bearer ${token}`
266
+ "Content-Type": "application/json"
262
267
  },
263
268
  method: "POST",
264
269
  body: JSON.stringify(sendModel)
@@ -293,6 +298,7 @@ const updateTable = async () => {
293
298
  return response;
294
299
  };
295
300
  const sortServer = (order, id) => {
301
+ if (!sendModel) throw new Error("Server-side configuration is missing");
296
302
  if (order === void 0) {
297
303
  sendModel.order = [];
298
304
  } else {
@@ -304,16 +310,19 @@ const sortServer = (order, id) => {
304
310
  $: sortKeys = pluginStates.sort.sortKeys;
305
311
  $: serverSide && updateTable();
306
312
  $: serverSide && sortServer($sortKeys[0]?.order, $sortKeys[0]?.id);
313
+ $: $hiddenColumnIds = shownColumns.filter((col) => !col.visible).map((col) => col.id);
307
314
  </script>
308
315
 
309
316
  <div class="grid gap-2 overflow-auto" class:w-fit={!fitToScreen} class:w-full={fitToScreen}>
310
317
  {#if $data.length > 0 || (columns && Object.keys(columns).length > 0)}
311
318
  <div class="table-container">
312
319
  <!-- Enable the search filter if table is not empty -->
313
- {#if !serverSide && search}
320
+ {#if search}
314
321
  <form
315
322
  class="flex gap-2"
316
323
  on:submit|preventDefault={() => {
324
+ if (!sendModel) throw new Error('Server-side configuration is missing');
325
+
317
326
  sendModel.q = searchValue;
318
327
  $filterValue = searchValue;
319
328
  }}
@@ -330,6 +339,8 @@ $: serverSide && sortServer($sortKeys[0]?.order, $sortKeys[0]?.id);
330
339
  id="{tableId}-searchReset"
331
340
  class="absolute right-3 items-center"
332
341
  on:click|preventDefault={() => {
342
+ if (!sendModel) throw new Error('Server-side configuration is missing');
343
+
333
344
  searchValue = '';
334
345
  sendModel.q = '';
335
346
  $filterValue = '';
@@ -341,6 +352,8 @@ $: serverSide && sortServer($sortKeys[0]?.order, $sortKeys[0]?.id);
341
352
  id="{tableId}-searchSubmit"
342
353
  class="btn variant-filled-primary"
343
354
  on:click|preventDefault={() => {
355
+ if (!sendModel) throw new Error('Server-side configuration is missing');
356
+
344
357
  $filterValue = searchValue;
345
358
  sendModel.q = searchValue;
346
359
  }}>Search</button
@@ -381,6 +394,9 @@ $: serverSide && sortServer($sortKeys[0]?.order, $sortKeys[0]?.id);
381
394
  >Export as CSV</button
382
395
  >
383
396
  {/if}
397
+ {#if shownColumns.length > 0}
398
+ <ColumnsMenu bind:columns={shownColumns} {tableId} />
399
+ {/if}
384
400
  </div>
385
401
  </div>
386
402
 
@@ -433,9 +449,7 @@ $: serverSide && sortServer($sortKeys[0]?.order, $sortKeys[0]?.id);
433
449
  <!-- Adding column filter config -->
434
450
  {#if cell.isData()}
435
451
  {#if props.colFilter?.render}
436
- <div class="">
437
- <Render of={props.colFilter.render} />
438
- </div>
452
+ <Render of={props.colFilter.render} />
439
453
  {/if}
440
454
  {/if}
441
455
  </div>
@@ -506,3 +520,5 @@ $: serverSide && sortServer($sortKeys[0]?.order, $sortKeys[0]?.id);
506
520
  {/if}
507
521
  {/if}
508
522
  </div>
523
+
524
+ <div id="{tableId}-popups" />
@@ -1,4 +1,5 @@
1
- <script>import Fa from "svelte-fa";
1
+ <script>import Fa from "svelte-fa/src/fa.svelte";
2
+ import { onMount } from "svelte";
2
3
  import { faFilter, faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
3
4
  import { popup } from "@skeletonlabs/skeleton";
4
5
  import { FilterOptionsEnum } from "../../models/Enums";
@@ -146,7 +147,8 @@ const optionChangeHandler = (e, index) => {
146
147
  const valueChangeHandler = (e, index) => {
147
148
  dropdowns[index] = {
148
149
  ...dropdowns[index],
149
- value: type === "date" ? new Date(e.target.value) : e.target.value
150
+ value: type === "date" ? new Date(e.target.value) : e.target.value,
151
+ formValue: e.target.value
150
152
  };
151
153
  $filters = {
152
154
  ...$filters,
@@ -166,7 +168,8 @@ const addFilter = (option, value) => {
166
168
  ...dropdowns,
167
169
  {
168
170
  option,
169
- value: void 0
171
+ value: void 0,
172
+ formValue: void 0
170
173
  }
171
174
  ];
172
175
  };
@@ -184,9 +187,14 @@ $: remainingFilters = options[type].filter(
184
187
  (option) => !Object.keys($filters[id]).includes(option.value)
185
188
  );
186
189
  $: addFilter(options[type][0].value, void 0);
190
+ onMount(() => {
191
+ const element = document.getElementById(popupId);
192
+ element?.parentElement?.removeChild(element);
193
+ element && document.getElementById(`${tableId}-popups`)?.appendChild(element);
194
+ });
187
195
  </script>
188
196
 
189
- <form class="">
197
+ <div id="parent-{popupId}">
190
198
  <button
191
199
  class:variant-filled-primary={active}
192
200
  class="btn w-max p-2"
@@ -197,7 +205,7 @@ $: addFilter(options[type][0].value, void 0);
197
205
  <Fa icon={faFilter} size="12" />
198
206
  </button>
199
207
 
200
- <div data-popup={`${popupId}`} id={popupId} class="z-50">
208
+ <div data-popup={popupId} id={popupId} class="">
201
209
  <div class="card p-3 grid gap-2 shadow-lg w-max bg-base-100">
202
210
  <button
203
211
  class="btn variant-filled-primary btn-sm"
@@ -255,7 +263,7 @@ $: addFilter(options[type][0].value, void 0);
255
263
  type="date"
256
264
  class="input p-1 border border-primary-500"
257
265
  on:input={(e) => valueChangeHandler(e, index)}
258
- bind:value={dropdown.value}
266
+ bind:value={dropdown.formValue}
259
267
  />
260
268
  {/if}
261
269
  </div>
@@ -289,4 +297,4 @@ $: addFilter(options[type][0].value, void 0);
289
297
  >
290
298
  </div>
291
299
  </div>
292
- </form>
300
+ </div>
@@ -134,7 +134,8 @@ const optionChangeHandler = (e, index) => {
134
134
  const valueChangeHandler = (e, index) => {
135
135
  dropdowns[index] = {
136
136
  ...dropdowns[index],
137
- value: type === "date" ? new Date(e.target.value) : e.target.value
137
+ value: type === "date" ? new Date(e.target.value) : e.target.value,
138
+ formValue: e.target.value
138
139
  };
139
140
  $filters = {
140
141
  ...$filters,
@@ -150,7 +151,8 @@ const addFilter = (option, value) => {
150
151
  ...dropdowns,
151
152
  {
152
153
  option,
153
- value: void 0
154
+ value: void 0,
155
+ formValue: void 0
154
156
  }
155
157
  ];
156
158
  };
@@ -3,8 +3,10 @@ import {
3
3
  faAnglesRight,
4
4
  faAngleRight,
5
5
  faAnglesLeft,
6
- faAngleLeft
6
+ faAngleLeft,
7
+ faChevronDown
7
8
  } from "@fortawesome/free-solid-svg-icons";
9
+ import { ListBox, ListBoxItem, popup } from "@skeletonlabs/skeleton";
8
10
  export let pageConfig;
9
11
  export let pageSizes;
10
12
  export let id;
@@ -23,24 +25,48 @@ const handleChange = (e) => {
23
25
  $pageIndex = value - 1;
24
26
  }
25
27
  };
28
+ let pageSizeDropdownValue = $pageSize;
29
+ const pageSizePopup = {
30
+ event: "click",
31
+ target: `#${id}-pageSizeDropdown`,
32
+ placement: "bottom",
33
+ closeQuery: ".listbox-item"
34
+ };
26
35
  $: goToFirstPageDisabled = !$pageIndex;
27
36
  $: goToLastPageDisabled = $pageIndex == $pageCount - 1;
28
37
  $: goToNextPageDisabled = !$hasNextPage;
29
38
  $: goToPreviousPageDisabled = !$hasPreviousPage;
39
+ $: $pageSize = pageSizeDropdownValue;
30
40
  </script>
31
41
 
32
- <div class="flex justify-between w-full items-stretch gap-10">
42
+ <div class="flex justify-between w-full items-stretch gap-10 z-50">
33
43
  <div class="flex justify-start">
34
- <select
44
+ <!-- <select
35
45
  name="pageSize"
36
46
  id="{id}-pageSize"
37
47
  class="select variant-filled-primary w-min font-bold"
38
48
  bind:value={$pageSize}
39
49
  >
40
50
  {#each pageSizes as size}
41
- <option value={size}>{size}</option>
51
+ <option value={size} class="">{size}</option>
42
52
  {/each}
43
- </select>
53
+ </select> -->
54
+
55
+ <button class="btn variant-filled-primary w-20 justify-between" use:popup={pageSizePopup}>
56
+ <span class="capitalize font-semibold">{pageSizeDropdownValue}</span>
57
+ <Fa icon={faChevronDown} size="xs" />
58
+ </button>
59
+
60
+ <div class="card w-20 shadow-xl py-2" data-popup={`#${id}-pageSizeDropdown`}>
61
+ <ListBox rounded="rounded-none">
62
+ {#each pageSizes as size}
63
+ <ListBoxItem bind:group={pageSizeDropdownValue} name="medium" value={size}
64
+ >{size}</ListBoxItem
65
+ >
66
+ {/each}
67
+ </ListBox>
68
+ <div class="arrow bg-surface-100-800-token" />
69
+ </div>
44
70
  </div>
45
71
  <div class="flex justify-center gap-1">
46
72
  <button
@@ -63,7 +63,7 @@ updateTable();
63
63
  bind:value={$pageSize}
64
64
  >
65
65
  {#each pageSizes as size}
66
- <option value={size}>{size}</option>
66
+ <option value={size} class="!bg-primary-700">{size}</option>
67
67
  {/each}
68
68
  </select>
69
69
  </div>