@bexis2/bexis2-core-ui 0.4.18 → 0.4.20

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 (58) hide show
  1. package/README.md +16 -8
  2. package/dist/components/CodeEditor/CodeEditor.svelte +4 -0
  3. package/dist/components/Facets/Facets.svelte +57 -20
  4. package/dist/components/Facets/Facets.svelte.d.ts +5 -1
  5. package/dist/components/Facets/ShowMore.svelte +31 -18
  6. package/dist/components/Facets/ShowMore.svelte.d.ts +2 -2
  7. package/dist/components/File/FileUploader.svelte +1 -1
  8. package/dist/components/Table/ColumnsMenu.svelte +5 -0
  9. package/dist/components/Table/TableContent.svelte +32 -16
  10. package/dist/components/Table/TableFilter.svelte +12 -0
  11. package/dist/components/Table/TableFilterServer.svelte +13 -1
  12. package/dist/components/Table/TablePagination.svelte +11 -6
  13. package/dist/components/Table/TablePaginationServer.svelte +8 -0
  14. package/dist/components/form/Checkbox.svelte +1 -1
  15. package/dist/components/form/CheckboxKvPList.svelte +2 -1
  16. package/dist/components/form/CheckboxList.svelte +2 -2
  17. package/dist/components/form/DateInput.svelte +1 -1
  18. package/dist/components/form/DropdownKvP.svelte +1 -1
  19. package/dist/components/form/InputContainer.svelte +7 -1
  20. package/dist/components/form/MultiSelect.svelte +100 -106
  21. package/dist/components/form/NumberInput.svelte +1 -1
  22. package/dist/components/form/TextArea.svelte +1 -1
  23. package/dist/components/form/TextInput.svelte +1 -1
  24. package/dist/components/page/Alert.svelte +1 -1
  25. package/dist/components/page/BackToTop.svelte +1 -1
  26. package/dist/components/page/Docs.svelte +1 -1
  27. package/dist/components/page/GoToTop.svelte +1 -0
  28. package/dist/components/page/HelpPopUp.svelte +1 -0
  29. package/dist/components/page/Page.svelte +14 -19
  30. package/dist/components/page/menu/MenuSublist.svelte +7 -5
  31. package/package.json +114 -114
  32. package/src/lib/components/CodeEditor/CodeEditor.svelte +4 -0
  33. package/src/lib/components/Facets/Facets.svelte +74 -25
  34. package/src/lib/components/Facets/ShowMore.svelte +33 -19
  35. package/src/lib/components/File/FileUploader.svelte +1 -1
  36. package/src/lib/components/Table/ColumnsMenu.svelte +5 -0
  37. package/src/lib/components/Table/TableContent.svelte +32 -16
  38. package/src/lib/components/Table/TableFilter.svelte +12 -0
  39. package/src/lib/components/Table/TableFilterServer.svelte +13 -1
  40. package/src/lib/components/Table/TablePagination.svelte +11 -6
  41. package/src/lib/components/Table/TablePaginationServer.svelte +8 -0
  42. package/src/lib/components/form/Checkbox.svelte +1 -1
  43. package/src/lib/components/form/CheckboxKvPList.svelte +2 -1
  44. package/src/lib/components/form/CheckboxList.svelte +2 -2
  45. package/src/lib/components/form/DateInput.svelte +1 -1
  46. package/src/lib/components/form/DropdownKvP.svelte +1 -1
  47. package/src/lib/components/form/InputContainer.svelte +7 -1
  48. package/src/lib/components/form/MultiSelect.svelte +100 -106
  49. package/src/lib/components/form/NumberInput.svelte +1 -1
  50. package/src/lib/components/form/TextArea.svelte +1 -1
  51. package/src/lib/components/form/TextInput.svelte +1 -1
  52. package/src/lib/components/page/Alert.svelte +1 -1
  53. package/src/lib/components/page/BackToTop.svelte +1 -1
  54. package/src/lib/components/page/Docs.svelte +1 -1
  55. package/src/lib/components/page/GoToTop.svelte +1 -0
  56. package/src/lib/components/page/HelpPopUp.svelte +1 -0
  57. package/src/lib/components/page/Page.svelte +15 -20
  58. package/src/lib/components/page/menu/MenuSublist.svelte +11 -8
package/README.md CHANGED
@@ -1,12 +1,20 @@
1
1
  # bexis-core-ui
2
+
3
+ ## 0.4.20
4
+ - Add aria-label to Table and other components
5
+ - Facets
6
+ - Add aria-label to Facets component
7
+ - sort by count if exists, reorder more view, truncate long names,
8
+ - Search
9
+ - Add aria-label to Search component
10
+ - Table: add column
11
+ ## 0.4.19
12
+
2
13
  ## 0.4.18
3
14
  - Updates indicator text for current page and possible number of pages in a Table
4
15
  - Fixes client-side search on Table
5
16
  - Adds "No rows available" text in Table if search or filter returns no rows.
6
17
 
7
- ## 0.4.17
8
- - Table
9
- - Fix client-side search
10
18
  ## 0.4.16
11
19
  - Facets
12
20
  - Replaces groups array with a writable store to re-render component on data manipulation.
@@ -18,9 +26,9 @@
18
26
  - Adds on:change action
19
27
 
20
28
  ## 0.4.14
21
- - Table
29
+ - Table
22
30
  - fixes rendering issues with Table filters and different components
23
-
31
+
24
32
  - Facets
25
33
  - Exports Facets component
26
34
 
@@ -44,7 +52,7 @@
44
52
  - Updates the structure of server-side configuration for Tables.
45
53
  - Adds new page size dropdown in Table for to fix contrast issues in the component.
46
54
  - Adds showing/hiding Table columns.
47
-
55
+
48
56
  - Facets:
49
57
  - Adds Facets component.
50
58
 
@@ -72,7 +80,7 @@
72
80
  - update libs
73
81
  - remove eslint-plugin-svelte3
74
82
  - update svelte, sveltekit, typescript, tailwind ...
75
-
83
+
76
84
  ## 0.4.3
77
85
  - table
78
86
  - Enable searching on server-side
@@ -103,7 +111,7 @@
103
111
 
104
112
  ## 0.3.11
105
113
  - add on:change passthrough to TextInput, TextArea, DateInput, NumberInput, CheckBox
106
-
114
+
107
115
  ## 0.3.10
108
116
  - multi select
109
117
  - update svelte-select libary
@@ -82,6 +82,7 @@ $: isValid = language === "json" ? isValidJSON(value) : language === "js" ? isVa
82
82
  <div class="flex gap-2">
83
83
  <button
84
84
  class="btn variant-filled-warning"
85
+ title="Reset"
85
86
  id="{id}-reset"
86
87
  on:click|preventDefault={() => modalStore.trigger(modal)}
87
88
  ><Fa icon={faArrowRotateLeft} /></button
@@ -90,6 +91,7 @@ $: isValid = language === "json" ? isValidJSON(value) : language === "js" ? isVa
90
91
  class="btn border"
91
92
  class:bg-slate-700={dark}
92
93
  class:bg-white={!dark}
94
+ title="Toggle dark mode"
93
95
  id="{id}-toggle"
94
96
  on:click|preventDefault={() => (dark = !dark)}
95
97
  >
@@ -106,11 +108,13 @@ $: isValid = language === "json" ? isValidJSON(value) : language === "js" ? isVa
106
108
  <div class="flex gap-2">
107
109
  <button
108
110
  class="btn variant-filled-warning"
111
+ title="Cancel"
109
112
  id="{id}-cancel"
110
113
  on:click|preventDefault={() => dispatch('cancel')}><Fa icon={faXmark} /></button
111
114
  >
112
115
  <button
113
116
  class="btn variant-filled-primary"
117
+ title="Save"
114
118
  id="{id}-save"
115
119
  disabled={!isValid}
116
120
  on:click|preventDefault={() => dispatch('save')}><Fa icon={faSave} /></button
@@ -5,12 +5,12 @@ export let groupSelection = false;
5
5
  export let groups;
6
6
  export let showAll = false;
7
7
  export let open = false;
8
- let selected;
9
- let selectedItems = {};
10
- let selectedGroups = {};
11
- const dispatch = createEventDispatcher();
12
- const modalStore = getModalStore();
13
- const showMore = (group) => {
8
+ export const showMore = (groupName) => {
9
+ const group = selected[groupName];
10
+ dispatch("showMoreOpenChange", {
11
+ group: group.name,
12
+ open: true
13
+ });
14
14
  modalStore.trigger({
15
15
  type: "component",
16
16
  title: `${group.displayName}`,
@@ -18,19 +18,43 @@ const showMore = (group) => {
18
18
  ref: ShowMore,
19
19
  props: {
20
20
  group,
21
- handleSave,
21
+ handleApply,
22
22
  handleCancel
23
23
  }
24
24
  }
25
25
  });
26
26
  };
27
- const handleSave = (group) => {
28
- Object.keys(group.children).forEach((key) => {
29
- selectedItems[group.name][key] = group.children[key].selected || false;
27
+ let selected;
28
+ let selectedItems = {};
29
+ let selectedGroups = {};
30
+ const dispatch = createEventDispatcher();
31
+ const modalStore = getModalStore();
32
+ const handleApply = (group) => {
33
+ const { name: groupName, children } = group;
34
+ dispatch("showMoreOpenChange", {
35
+ group: groupName,
36
+ open: false
30
37
  });
38
+ for (const key in children) {
39
+ const selectedValue = children[key].selected || false;
40
+ selectedItems[groupName][key] = selectedValue;
41
+ if (selected[groupName].children[key].selected !== selectedValue) {
42
+ selected[groupName].children[key].selected = selectedValue;
43
+ }
44
+ }
45
+ dispatch("showMoreSelect", [
46
+ {
47
+ parent: groupName,
48
+ selected: Object.keys(children).map((key) => children[key].selected)
49
+ }
50
+ ]);
31
51
  modalStore.close();
32
52
  };
33
- const handleCancel = () => {
53
+ const handleCancel = (groupName) => {
54
+ dispatch("showMoreOpenChange", {
55
+ group: groupName,
56
+ open: false
57
+ });
34
58
  modalStore.close();
35
59
  };
36
60
  const mapSelected = (type) => {
@@ -58,7 +82,7 @@ const mapSelected = (type) => {
58
82
  }
59
83
  });
60
84
  }
61
- changed.length && dispatch("change", changed);
85
+ changed.length && dispatch("facetSelect", changed);
62
86
  };
63
87
  const sortOptions = () => {
64
88
  Object.keys(selected).forEach((group) => {
@@ -66,11 +90,14 @@ const sortOptions = () => {
66
90
  if (a.count != void 0 && b.count != void 0) {
67
91
  return b.count - a.count;
68
92
  }
69
- return a.displayName.localeCompare(b.displayName);
93
+ return 0;
94
+ }).map((item) => item.name);
95
+ const unchecked = Object.keys(selected[group].children).filter((item) => !checked.includes(item)).map((item) => selected[group].children[item]).sort((a, b) => {
96
+ if (a.count != void 0 && b.count != void 0) {
97
+ return b.count - a.count;
98
+ }
99
+ return 0;
70
100
  }).map((item) => item.name);
71
- const unchecked = Object.keys(selected[group].children).filter(
72
- (item) => !checked.includes(item)
73
- );
74
101
  const groupIndex = displayedGroups.findIndex((g) => g.name === group);
75
102
  displayedGroups[groupIndex].children = [
76
103
  ...checked.map(
@@ -121,7 +148,7 @@ $: selectedGroups, mapSelected("groups");
121
148
  bind:checked={selectedGroups[group.name]}
122
149
  bind:group={selectedGroups}
123
150
  >
124
- <p class="font-semibold">
151
+ <p class="font-semibold whitespace-nowrap">
125
152
  {group.displayName}{group.count !== undefined ? ` (${group.count})` : ''}
126
153
  </p>
127
154
 
@@ -139,13 +166,18 @@ $: selectedGroups, mapSelected("groups");
139
166
  selection
140
167
  multiple
141
168
  >
142
- <p>{item.displayName} ({item.count})</p>
169
+ <div class="flex gap-2">
170
+ <p class="w-max grow truncate">
171
+ <span title={item.displayName}>{item.displayName}</span>
172
+ </p>
173
+ <span>({item.count})</span>
174
+ </div>
143
175
  </TreeViewItem>
144
176
  {/each}
145
177
  <!-- Trigger for the Modal to view all options -->
146
178
  {#if group.children.length > 5}
147
179
  <TreeViewItem hyphenOpacity="opacity-0">
148
- <button class="anchor" on:click={() => showMore(selected[group.name])}>more</button
180
+ <button class="anchor" on:click={() => showMore(group.name)}>more</button
149
181
  ></TreeViewItem
150
182
  >
151
183
  {/if}
@@ -161,7 +193,12 @@ $: selectedGroups, mapSelected("groups");
161
193
  selection
162
194
  multiple
163
195
  >
164
- <p>{item.displayName} ({item.count})</p>
196
+ <div class="flex gap-2">
197
+ <p class="w-max grow truncate">
198
+ <span title={item.displayName}>{item.displayName}</span>
199
+ </p>
200
+ <span>({item.count})</span>
201
+ </div>
165
202
  </TreeViewItem>
166
203
  {/each}
167
204
  {/if}
@@ -7,9 +7,12 @@ declare const __propDef: {
7
7
  groups: Writable<FacetGroup[]>;
8
8
  showAll?: boolean;
9
9
  open?: boolean;
10
+ showMore?: (groupName: string) => void;
10
11
  };
11
12
  events: {
12
- change: CustomEvent<any>;
13
+ showMoreOpenChange: CustomEvent<any>;
14
+ showMoreSelect: CustomEvent<any>;
15
+ facetSelect: CustomEvent<any>;
13
16
  } & {
14
17
  [evt: string]: CustomEvent<any>;
15
18
  };
@@ -19,5 +22,6 @@ export type FacetsProps = typeof __propDef.props;
19
22
  export type FacetsEvents = typeof __propDef.events;
20
23
  export type FacetsSlots = typeof __propDef.slots;
21
24
  export default class Facets extends SvelteComponent<FacetsProps, FacetsEvents, FacetsSlots> {
25
+ get showMore(): (groupName: string) => void;
22
26
  }
23
27
  export {};
@@ -1,5 +1,5 @@
1
1
  <script>export let group;
2
- export let handleSave;
2
+ export let handleApply;
3
3
  export let handleCancel;
4
4
  let selected = structuredClone(group.children);
5
5
  const selectAll = () => {
@@ -8,8 +8,8 @@ const selectAll = () => {
8
8
  const selectNone = () => {
9
9
  Object.keys(selected).forEach((key) => selected[key].selected = false);
10
10
  };
11
- const onSave = () => {
12
- handleSave({
11
+ const onApply = () => {
12
+ handleApply({
13
13
  ...group,
14
14
  children: selected
15
15
  });
@@ -17,34 +17,47 @@ const onSave = () => {
17
17
  const onCancel = () => {
18
18
  console.log(selected, group.children);
19
19
  selected = structuredClone(group.children);
20
- handleCancel();
20
+ handleCancel(group.name);
21
21
  };
22
22
  const gridClass = (items) => {
23
- if (items.length >= 50) {
24
- return "grid-cols-5";
25
- } else if (items.length >= 30) {
26
- return "grid-cols-4";
27
- } else if (items.length >= 20) {
28
- return "grid-cols-3";
29
- }
30
- return "grid-cols-2";
23
+ const ceil = Math.ceil(Math.sqrt(items.length));
24
+ const max = Math.max(ceil, Math.floor(items.length / 3));
25
+ const classes = [
26
+ "grid-rows-1",
27
+ "grid-rows-2",
28
+ "grid-rows-3",
29
+ "grid-rows-4",
30
+ "grid-rows-5",
31
+ "grid-rows-6",
32
+ "grid-rows-7",
33
+ "grid-rows-8",
34
+ "grid-rows-9",
35
+ "grid-rows-10",
36
+ "grid-rows-11",
37
+ "grid-rows-12"
38
+ ];
39
+ if (max > 12) {
40
+ return "grid-rows-12";
41
+ } else return classes[max - 1 || 1];
31
42
  };
32
43
  </script>
33
44
 
34
- <div class="p-5 rounded-md bg-surface-50 dark:bg-surface-800 border-primary-500 border-2">
45
+ <div class="p-5 rounded-md max-w-6xl bg-surface-50 dark:bg-surface-800 border-primary-500 border-2">
35
46
  <!-- Header -->
36
47
  <h2 class="text-xl font-semibold">{group.displayName}</h2>
37
48
 
38
49
  <!-- Items -->
39
50
  <div
40
- class="grid {gridClass(
51
+ class="{gridClass(
41
52
  Object.keys(selected)
42
- )} !gap-x-20 gap-y-2 py-10 px-2 max-h-[1000px] overflow-x-auto max-w-6xl"
53
+ )} grid grid-flow-col gap-x-10 gap-y-2 py-10 px-2 h-full overflow-x-auto"
43
54
  >
44
55
  {#each Object.keys(selected) as key}
45
- <label class="flex gap-3 items-center">
56
+ <label class="flex gap-3 items-center w-48">
46
57
  <input type="checkbox" class="checkbox" bind:checked={selected[key].selected} />
47
- <span class="whitespace-nowrap break-before-avoid break-after-avoid"
58
+ <span
59
+ title={selected[key].displayName}
60
+ class="whitespace-nowrap break-before-avoid break-after-avoid truncate"
48
61
  >{selected[key].displayName}</span
49
62
  >
50
63
  </label>
@@ -58,7 +71,7 @@ const gridClass = (items) => {
58
71
  <button class="btn btn-sm variant-filled-tertiary" on:click={selectAll}>All</button>
59
72
  </div>
60
73
  <div class="flex gap-3">
61
- <button class="btn btn-sm variant-filled-primary" on:click={onSave}>Save</button>
74
+ <button class="btn btn-sm variant-filled-primary" on:click={onApply}>Apply</button>
62
75
  <button class="btn btn-sm variant-filled-secondary" on:click={onCancel}>Cancel</button>
63
76
  </div>
64
77
  </div>
@@ -3,8 +3,8 @@ import type { SelectedFacetGroup } from '../../models/Models';
3
3
  declare const __propDef: {
4
4
  props: {
5
5
  group: SelectedFacetGroup;
6
- handleSave: (group: SelectedFacetGroup) => {};
7
- handleCancel: () => {};
6
+ handleApply: (group: SelectedFacetGroup) => {};
7
+ handleCancel: (groupName: string) => {};
8
8
  };
9
9
  events: {
10
10
  [evt: string]: CustomEvent<any>;
@@ -121,7 +121,7 @@ async function handleSubmit() {
121
121
  {/if}
122
122
  </div>
123
123
 
124
- <button id={submitBt} color="primary" style="display:none"><Fa icon={faSave} /></button>
124
+ <button title="Submit" id={submitBt} color="primary" style="display:none"><Fa icon={faSave} /></button>
125
125
  {:else}
126
126
  <!-- while data is not loaded show a loading information -->
127
127
 
@@ -10,7 +10,9 @@ const popupCombobox = {
10
10
 
11
11
  <button
12
12
  type="button"
13
+ title="Hide or show columns"
13
14
  class="btn btn-sm variant-filled-primary rounded-full order-last"
15
+ aria-label="Open menu to hide/show columns"
14
16
  use:popup={popupCombobox}>Columns</button
15
17
  >
16
18
 
@@ -20,8 +22,11 @@ const popupCombobox = {
20
22
  >
21
23
  {#each columns as column}
22
24
  <div class="flex gap-3 items-center">
25
+ <label for={column.id} class="cursor-pointer" title={column.label}></label>
23
26
  <input
27
+ aria-label="Toggle column visibility for column {column.label}"
24
28
  type="checkbox"
29
+ id = {column.id}
25
30
  bind:checked={column.visible}
26
31
  disabled={columns.filter((c) => c.visible).length === 1 && column.visible}
27
32
  />
@@ -143,8 +143,8 @@ const tableColumns = [
143
143
  header: header ?? key,
144
144
  accessor,
145
145
  // Render the cell with the provided component, or use the toStringFn if provided, or just use the value
146
- cell: ({ value, row }) => {
147
- return renderComponent ? createRender(renderComponent, { value, row, dispatchFn: actionDispatcher }) : toStringFn ? toStringFn(value) : value;
146
+ cell: ({ value, row, column }) => {
147
+ return renderComponent ? createRender(renderComponent, { value, row, column, dispatchFn: actionDispatcher }) : toStringFn ? toStringFn(value) : value;
148
148
  },
149
149
  plugins: {
150
150
  // Sorting config
@@ -322,10 +322,11 @@ $: $hiddenColumnIds = shownColumns.filter((col) => !col.visible).map((col) => co
322
322
  class="flex gap-2"
323
323
  on:submit|preventDefault={() => {
324
324
  if (serverSide && !sendModel) {
325
- throw new Error('Server-side configuration is missing');
326
- } else {
327
- sendModel.q = searchValue;
328
- }
325
+ throw new Error('Server-side configuration is missing');
326
+ } else {
327
+ sendModel.q = searchValue;
328
+ }
329
+
329
330
  $filterValue = searchValue;
330
331
  }}
331
332
  >
@@ -333,21 +334,22 @@ sendModel.q = searchValue;
333
334
  <input
334
335
  class="input p-2 border border-primary-500"
335
336
  type="text"
337
+ title="Search within all table rows"
336
338
  bind:value={searchValue}
337
339
  placeholder="Search rows..."
338
340
  id="{tableId}-search"
339
341
  /><button
340
342
  type="reset"
343
+ title="Clear search"
341
344
  id="{tableId}-searchReset"
342
345
  class="absolute right-3 items-center"
346
+ aria-label="Clear search"
343
347
  on:click|preventDefault={() => {
344
348
  if (serverSide && !sendModel) {
345
- throw new Error('Server-side configuration is missing');
346
- } else {
347
- sendModel.q = '';
348
- }
349
-
350
- $filterValue = searchValue;
349
+ throw new Error('Server-side configuration is missing');
350
+ } else {
351
+ sendModel.q = '';
352
+ }
351
353
 
352
354
  searchValue = '';
353
355
  $filterValue = '';
@@ -356,14 +358,15 @@ sendModel.q = '';
356
358
  </div>
357
359
  <button
358
360
  type="submit"
361
+ title="Search"
359
362
  id="{tableId}-searchSubmit"
360
363
  class="btn variant-filled-primary"
361
364
  on:click|preventDefault={() => {
362
365
  if (serverSide && !sendModel) {
363
- throw new Error('Server-side configuration is missing');
364
- } else {
365
- sendModel.q = searchValue;
366
- }
366
+ throw new Error('Server-side configuration is missing');
367
+ } else {
368
+ sendModel.q = searchValue;
369
+ }
367
370
 
368
371
  $filterValue = searchValue;
369
372
  }}>Search</button
@@ -381,6 +384,7 @@ sendModel.q = searchValue;
381
384
  {#if toggle}
382
385
  <SlideToggle
383
386
  name="slider-label"
387
+ label="Fit to screen"
384
388
  active="bg-primary-500"
385
389
  size="sm"
386
390
  checked={fitToScreen}
@@ -394,6 +398,7 @@ sendModel.q = searchValue;
394
398
  {#if resizable !== 'none'}
395
399
  <button
396
400
  type="button"
401
+ title="Reset column and row sizing"
397
402
  class="btn btn-sm variant-filled-primary rounded-full order-last"
398
403
  on:click|preventDefault={() =>
399
404
  resetResize($headerRows, $pageRows, tableId, columns, resizable)}
@@ -403,6 +408,7 @@ sendModel.q = searchValue;
403
408
  {#if exportable}
404
409
  <button
405
410
  type="button"
411
+ title="Export table data as CSV"
406
412
  class="btn btn-sm variant-filled-primary rounded-full order-last"
407
413
  on:click|preventDefault={() => exportAsCsv(tableId, $exportedData)}
408
414
  >Export as CSV</button
@@ -419,6 +425,7 @@ sendModel.q = searchValue;
419
425
  {...$tableAttrs}
420
426
  class="table table-auto table-compact bg-tertiary-500/30 dark:bg-tertiary-900/10 overflow-clip"
421
427
  id="{tableId}-table"
428
+ title="Table"
422
429
  >
423
430
  <!-- If table height is provided, making the top row sticky -->
424
431
  <thead class={height != null && $pageRows.length > 0 ? `sticky top-0` : ''}>
@@ -444,6 +451,8 @@ sendModel.q = searchValue;
444
451
  <div class="flex gap-1 whitespace-pre-wrap">
445
452
  <!-- Adding sorting config and styling -->
446
453
  <span
454
+ role="button"
455
+ tabindex="0"
447
456
  class:underline={props.sort.order}
448
457
  class:normal-case={cell.id !== cell.label}
449
458
  class:cursor-pointer={!props.sort.disabled}
@@ -506,6 +515,13 @@ sendModel.q = searchValue;
506
515
  {/each}
507
516
  </tbody>
508
517
  </table>
518
+ {#if $pageRows.length === 0}
519
+ <div
520
+ class="p-8 flex items-center justify-center bg-tertiary-500/30 dark:bg-tertiary-900/10"
521
+ >
522
+ No rows available
523
+ </div>
524
+ {/if}
509
525
  </div>
510
526
  </div>
511
527
  {:else}
@@ -201,6 +201,7 @@ onMount(() => {
201
201
  type="button"
202
202
  use:popup={popupFeatured}
203
203
  id="{popupId}-button"
204
+ aria-label="Open filter menu for column {id}"
204
205
  >
205
206
  <Fa icon={faFilter} size="12" />
206
207
  </button>
@@ -210,6 +211,7 @@ onMount(() => {
210
211
  <button
211
212
  class="btn variant-filled-primary btn-sm"
212
213
  type="button"
214
+ aria-label="Clear Filters"
213
215
  on:click|preventDefault={() => {
214
216
  // Set the defaults when cleared
215
217
  clearFilters();
@@ -234,6 +236,7 @@ onMount(() => {
234
236
  {#each options[type] as option (option)}
235
237
  <option
236
238
  value={option.value}
239
+ aria-label={option.label}
237
240
  selected={dropdown.option === option.value}
238
241
  disabled={Object.keys($filters[id]).includes(option.value) &&
239
242
  dropdown.option !== option.value}>{option.label}</option
@@ -242,7 +245,10 @@ onMount(() => {
242
245
  </select>
243
246
  {#if dropdowns.length > 1}
244
247
  <div
248
+ role="button"
249
+ tabindex="0"
245
250
  class="btn variant-filled-warning btn-sm h-full"
251
+ aria-label="Remove filter"
246
252
  on:click|preventDefault={() => removeFilter(dropdown.option)}
247
253
  on:keydown|preventDefault={() => removeFilter(dropdown.option)}
248
254
  >
@@ -257,6 +263,7 @@ onMount(() => {
257
263
  class="input p-1 border border-primary-500"
258
264
  on:input={(e) => valueChangeHandler(e, index)}
259
265
  bind:value={dropdown.value}
266
+ aria-label="Filter value"
260
267
  />
261
268
  {:else}
262
269
  <input
@@ -264,6 +271,7 @@ onMount(() => {
264
271
  class="input p-1 border border-primary-500"
265
272
  on:input={(e) => valueChangeHandler(e, index)}
266
273
  bind:value={dropdown.formValue}
274
+ aria-label="Filter value"
267
275
  />
268
276
  {/if}
269
277
  </div>
@@ -276,12 +284,15 @@ onMount(() => {
276
284
  {#if remainingFilters.length}
277
285
  <div
278
286
  class="btn variant-filled-secondary btn-sm cursor-pointer"
287
+ role="button"
288
+ tabindex="0"
279
289
  on:click|stopPropagation={() => {
280
290
  addFilter(remainingFilters[0].value, undefined);
281
291
  }}
282
292
  on:keydown|stopPropagation={() => {
283
293
  addFilter(remainingFilters[0].value, undefined);
284
294
  }}
295
+ aria-label="Add filter"
285
296
  >
286
297
  <div class="flex gap-1 items-center"><Fa icon={faPlus} />Add Filter</div>
287
298
  </div>
@@ -289,6 +300,7 @@ onMount(() => {
289
300
  <button
290
301
  class="btn variant-filled-primary btn-sm"
291
302
  type="button"
303
+ aria-label="Apply filters"
292
304
  on:click|preventDefault={() => {
293
305
  $pageIndex = 0;
294
306
  $filterValue = $filters[id];
@@ -190,6 +190,7 @@ $: console.log($filters);
190
190
  type="button"
191
191
  use:popup={popupFeatured}
192
192
  id="{popupId}-button"
193
+ aria-label="Open filter menu for column {id}"
193
194
  >
194
195
  <Fa icon={faFilter} size="12" />
195
196
  </button>
@@ -199,6 +200,7 @@ $: console.log($filters);
199
200
  <button
200
201
  class="btn variant-filled-primary btn-sm"
201
202
  type="button"
203
+ aria-label="Clear Filters"
202
204
  on:click|preventDefault={() => {
203
205
  // Set the defaults when cleared
204
206
  clearFilters();
@@ -221,6 +223,7 @@ $: console.log($filters);
221
223
  {#each options[type] as option (option)}
222
224
  <option
223
225
  value={option.value}
226
+ aria-label={option.label}
224
227
  selected={dropdown.option === option.value}
225
228
  disabled={Object.keys($filters[id]).includes(option.value) &&
226
229
  dropdown.option !== option.value}>{option.label}</option
@@ -229,10 +232,13 @@ $: console.log($filters);
229
232
  </select>
230
233
  {#if dropdowns.length > 1}
231
234
  <div
235
+ role="button"
236
+ tabindex="0"
232
237
  class="btn variant-filled-warning btn-sm h-full"
233
238
  on:click|preventDefault={() => removeFilter(dropdown.option)}
234
239
  on:keydown|preventDefault={() => removeFilter(dropdown.option)}
235
- >
240
+ aria-label="Remove filter"
241
+ >
236
242
  <Fa icon={faXmark} />
237
243
  </div>
238
244
  {/if}
@@ -251,6 +257,7 @@ $: console.log($filters);
251
257
  class="input p-1 border border-primary-500"
252
258
  on:input={(e) => valueChangeHandler(e, index)}
253
259
  bind:value={dropdown.value}
260
+ aria-label="Filter value"
254
261
  />
255
262
  {:else}
256
263
  <input
@@ -258,6 +265,7 @@ $: console.log($filters);
258
265
  class="input p-1 border border-primary-500"
259
266
  on:input={(e) => valueChangeHandler(e, index)}
260
267
  bind:value={dropdown.value}
268
+ aria-label="Filter value"
261
269
  />
262
270
  {/if}
263
271
  </div>
@@ -270,6 +278,9 @@ $: console.log($filters);
270
278
  {#if remainingFilters.length}
271
279
  <div
272
280
  class="btn variant-filled-secondary btn-sm cursor-pointer"
281
+ aria-label="Add filter"
282
+ role="button"
283
+ tabindex="0"
273
284
  on:click|stopPropagation={() => {
274
285
  addFilter(remainingFilters[0].value, undefined);
275
286
  }}
@@ -283,6 +294,7 @@ $: console.log($filters);
283
294
  <button
284
295
  class="btn variant-filled-primary btn-sm"
285
296
  type="button"
297
+ aria-label="Apply filters"
286
298
  on:click|preventDefault={applyFilters}>Apply</button
287
299
  >
288
300
  </div>