@likable-hair/svelte 3.0.19 → 3.0.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 (27) hide show
  1. package/dist/components/composed/forms/Dropdown.svelte +16 -7
  2. package/dist/components/composed/forms/Dropdown.svelte.d.ts +4 -0
  3. package/dist/components/composed/list/PaginatedTable.svelte +131 -133
  4. package/dist/components/composed/list/PaginatedTable.svelte.d.ts +68 -2
  5. package/dist/components/composed/list/Paginator.svelte +12 -6
  6. package/dist/components/composed/search/Filters.css +0 -0
  7. package/dist/components/composed/search/Filters.svelte +97 -0
  8. package/dist/components/composed/search/Filters.svelte.d.ts +26 -0
  9. package/dist/components/simple/buttons/Button.css +1 -0
  10. package/dist/components/simple/buttons/Button.svelte +4 -0
  11. package/dist/components/simple/forms/Autocomplete.svelte +5 -1
  12. package/dist/components/simple/forms/Autocomplete.svelte.d.ts +1 -0
  13. package/dist/components/simple/lists/SimpleTable.svelte +25 -23
  14. package/dist/components/simple/lists/SimpleTable.svelte.d.ts +3 -1
  15. package/dist/components/simple/lists/columnTypes.d.ts +35 -0
  16. package/dist/components/simple/lists/columnTypes.js +1 -0
  17. package/dist/index.d.ts +1 -0
  18. package/dist/index.js +1 -0
  19. package/dist/utils/filters/builder.d.ts +43 -0
  20. package/dist/utils/filters/builder.js +137 -0
  21. package/dist/utils/filters/filters.d.ts +26 -0
  22. package/dist/utils/filters/filters.js +29 -0
  23. package/dist/utils/filters/modifiers/join.d.ts +26 -0
  24. package/dist/utils/filters/modifiers/join.js +1 -0
  25. package/dist/utils/filters/modifiers/where.d.ts +29 -0
  26. package/dist/utils/filters/modifiers/where.js +1 -0
  27. package/package.json +1 -1
@@ -3,7 +3,7 @@
3
3
  <script>import Autocomplete from "../../../components/simple/forms/Autocomplete.svelte";
4
4
  import Button from "../../simple/buttons/Button.svelte";
5
5
  import Icon from "../../simple/media/Icon.svelte";
6
- export let items = [], values = [], multiple = false, searchText = void 0, maxVisibleChips = void 0, placeholder = "Seleziona", icon = void 0;
6
+ export let items = [], values = [], multiple = false, searchText = void 0, maxVisibleChips = void 0, placeholder = "Seleziona", clearable = true, mandatory = true, icon = void 0;
7
7
  $:
8
8
  generatedLabel = values.length == 1 ? values[0].label : `${values.length} Selezionati`;
9
9
  function handleCloseClick(event) {
@@ -19,11 +19,15 @@ function handleCloseClick(event) {
19
19
  bind:searchText
20
20
  bind:multiple
21
21
  bind:maxVisibleChips
22
+ bind:mandatory
22
23
  searchFunction={() => true}
24
+ on:change
23
25
  >
24
26
  <svelte:fragment slot="selection-container" let:openMenu let:handleKeyDown>
25
27
  <Button
26
28
  --button-default-background-color="transparent"
29
+ --button-default-focus-background-color="rgb(var(--global-color-primary-400), .3)"
30
+ --button-default-focus-color="rgb(var(--global-color-contrast-900))"
27
31
  --button-default-border="2px solid rgb(var(--global-color-primary-400))"
28
32
  --button-default-color="rgb(var(--global-color-contrast-800))"
29
33
  on:click={openMenu}
@@ -48,11 +52,13 @@ function handleCloseClick(event) {
48
52
  {:else}
49
53
  <div class="space-between">
50
54
  <div>{generatedLabel}</div>
51
- <Icon
52
- name="mdi-close"
53
- click
54
- on:click={handleCloseClick}
55
- ></Icon>
55
+ {#if clearable}
56
+ <Icon
57
+ name="mdi-close"
58
+ click
59
+ on:click={handleCloseClick}
60
+ ></Icon>
61
+ {/if}
56
62
  </div>
57
63
  {/if}
58
64
  </div>
@@ -67,7 +73,9 @@ function handleCloseClick(event) {
67
73
  justify-content: flex-start;
68
74
  align-items: center;
69
75
  gap: 10px;
70
- width: 130px;
76
+ width: 100%;
77
+ text-overflow: ellipsis;
78
+ white-space: pre;
71
79
  }
72
80
 
73
81
  .space-between {
@@ -75,5 +83,6 @@ function handleCloseClick(event) {
75
83
  display: flex;
76
84
  justify-content: space-between;
77
85
  align-items: center;
86
+ gap: 10px;
78
87
  }
79
88
  </style>
@@ -9,9 +9,13 @@ declare const __propDef: {
9
9
  searchText?: string | undefined;
10
10
  maxVisibleChips?: number | undefined;
11
11
  placeholder?: string | undefined;
12
+ clearable?: boolean | undefined;
13
+ mandatory?: boolean | undefined;
12
14
  icon?: string | undefined;
13
15
  };
14
16
  events: {
17
+ change: CustomEvent<any>;
18
+ } & {
15
19
  [evt: string]: CustomEvent<any>;
16
20
  };
17
21
  slots: {
@@ -1,152 +1,150 @@
1
- <!-- <script lang="ts" context="module">
2
- export type Header = {
3
- value: string;
4
- label: string;
5
- type: "boolean" | "string" | "number" | "date" | "custom";
6
- width?: string;
7
- minWidth?: string;
8
- data?: { [key: string]: any };
9
- };
1
+ <script context="module">import SimpleTable from "../../simple/lists/SimpleTable.svelte";
2
+ import Icon from "../../simple/media/Icon.svelte";
3
+ import Paginator from "./Paginator.svelte";
4
+ import Dropdown from "../forms/Dropdown.svelte";
5
+ import { createEventDispatcher } from "svelte";
10
6
  </script>
11
7
 
12
- <script lang="ts">
13
- import { onMount } from 'svelte';
14
- import type { Filter } from '../../../types/filter';
15
- import StandardPaginator from './StandardPaginator.svelte';
16
- import StandardSelect from './StandardSelect.svelte';
17
- import StandardTable from "./StandardTable.svelte";
18
-
19
- export let headers: Header[] = [],
20
- filters: Filter[] = [],
21
- width: string = "auto",
22
- page: number = 1,
23
- perPage: number = 20,
24
- perPageOptions: number[] = [20, 50, 100],
25
- reload: boolean = false,
26
- loading: boolean = false,
27
- loadingText: string = "Caricamento ...",
28
- noDataText: string = "Nessun elemento disponibile",
29
- fetcher: (params: {
30
- page: number,
31
- perPage: number,
32
- filters: Filter[]
33
- }) => Promise<{
34
- data: any[],
35
- meta: PaginationData
36
- }>
37
-
38
- let items: { [key: string]: any }[] = [],
39
- maxPage: number | undefined = undefined
40
-
41
- onMount(() => {
42
- loadRows()
43
- })
44
-
45
- async function loadRows() {
46
- if(!!fetcher) {
47
- loading = true
48
- let results = await fetcher({page, perPage, filters})
49
-
50
- items = results.data
51
- page = results.meta.currentPage
52
- maxPage = results.meta.lastPage
53
- loading = false
54
- }
55
- }
56
-
57
- function handlePaginationChange() {
58
- loadRows()
59
- }
60
-
61
- function handlePerPageChange() {
62
- page = 1
63
- loadRows()
64
- }
65
-
66
- $: perPageOptionsFormatted = perPageOptions.map((el) => {
67
- return {
68
- value: el,
69
- text: el.toString()
70
- }
71
- })
72
- $: if(reload) {
73
- loadRows().then(() => {
74
- reload = false
75
- })
76
- }
77
-
78
- $: filters && loadRows()
79
-
8
+ <script>let clazz = {};
9
+ export { clazz as class };
10
+ export let headers = [], items = [], sortedBy = void 0, sortDirection = void 0, page = 1, maxPage = void 0, rowsPerPageOptions = [
11
+ { label: "20", value: 20 },
12
+ { label: "50", value: 50 },
13
+ { label: "100", value: 100 }
14
+ ], hideRowsPerPage = false, totalElements = void 0, rowsPerPage = 20;
15
+ let dispatch = createEventDispatcher();
16
+ let rowsPerPageSelection = [];
17
+ $:
18
+ rowsPerPageSelection = [
19
+ { label: rowsPerPage.toString(), value: rowsPerPage }
20
+ ];
21
+ $:
22
+ if (totalElements !== void 0)
23
+ maxPage = Math.max(Math.round(totalElements / rowsPerPage), 1);
24
+ function handleRowsPerPageChange(e) {
25
+ rowsPerPage = Number(e.detail.selection?.[0].value);
26
+ handlePaginationChange();
27
+ }
28
+ function handlePaginationChange() {
29
+ dispatch("paginationChange", {
30
+ rowsPerPage,
31
+ page
32
+ });
33
+ }
80
34
  </script>
81
35
 
82
- <div class="top-actions">
83
-
84
- </div>
85
- <div class="table">
86
- <StandardTable
87
- headers={headers}
88
- width={width}
89
- items={items}
36
+ <div class="paginated-table">
37
+ <SimpleTable
38
+ bind:headers
39
+ bind:class={clazz.simpleTable}
40
+ bind:items
41
+ bind:sortedBy
42
+ bind:sortDirection
43
+ on:sort
90
44
  >
91
- <svelte:fragment slot="appendLastColumn" let:item>
92
- <slot name="appendLastColumn" item={item}></slot>
45
+ <svelte:fragment slot="header" let:head>
46
+ <slot name="header" {head} >
47
+ <span class="header-label">
48
+ <slot name="headerLabel">
49
+ {head.label}
50
+ </slot>
51
+ </span>
52
+ {#if head.sortable}
53
+ <span
54
+ class="header-sort-icon"
55
+ class:active={sortedBy == head.value}
56
+ class:asc={sortDirection == 'asc'}
57
+ class:desc={sortDirection == 'desc'}
58
+ >
59
+ {#if sortDirection == 'asc'}
60
+ <Icon name="mdi-arrow-up"></Icon>
61
+ {:else}
62
+ <Icon name="mdi-arrow-down"></Icon>
63
+ {/if}
64
+ </span>
65
+ {/if}
66
+ </slot>
93
67
  </svelte:fragment>
94
-
95
- <svelte:fragment slot="customColumn" let:item let:header>
96
- <slot name="customColumn" item={item} header={header}></slot>
68
+ <svelte:fragment
69
+ slot="custom"
70
+ let:columnIndex
71
+ let:index
72
+ let:header
73
+ let:item
74
+ >
75
+ <slot name="custom" {index} {columnIndex} {header} {item}/>
97
76
  </svelte:fragment>
98
- </StandardTable>
99
- {#if loading}
100
- <div class="loading-text">
101
- {loadingText}
102
- </div>
103
- {:else if items.length == 0}
104
- <div class="no-data">
105
- {noDataText}
106
- </div>
107
- {/if}
108
- </div>
109
- <div class="footer">
110
- <div>
111
- <StandardSelect
112
- bind:value={perPage}
113
- options={perPageOptionsFormatted}
114
- on:change={handlePerPageChange}
115
- ></StandardSelect>
116
- </div>
117
- <div>
118
- <StandardPaginator
119
- bind:page={page}
120
- bind:maxPage={maxPage}
121
- on:change={handlePaginationChange}
122
- ></StandardPaginator>
77
+ <svelte:fragment slot="rowActions" let:index let:item>
78
+ <slot name="rowActions" {index} {item} />
79
+ </svelte:fragment>
80
+ <svelte:fragment slot="append" let:index let:item>
81
+ <slot name="append" {index} {item} />
82
+ </svelte:fragment>
83
+ </SimpleTable>
84
+ <div class="footer">
85
+ <slot
86
+ name="footer"
87
+ {hideRowsPerPage}
88
+ {rowsPerPageOptions}
89
+ {rowsPerPageSelection}
90
+ {totalElements}
91
+ {page}
92
+ {maxPage}
93
+ {rowsPerPage}
94
+ {handlePaginationChange}
95
+ >
96
+ {#if !hideRowsPerPage}
97
+ <Dropdown
98
+ placeholder="Per pagina"
99
+ clearable={false}
100
+ mandatory={true}
101
+ bind:items={rowsPerPageOptions}
102
+ bind:values={rowsPerPageSelection}
103
+ --button-default-width="90px"
104
+ on:change={handleRowsPerPageChange}
105
+ ></Dropdown>
106
+ {/if}
107
+ {#if totalElements !== undefined}
108
+ <slot name="rangeDescriptor" {page} {maxPage} {rowsPerPage} {totalElements}>
109
+ <div class="range-descriptor">
110
+ viewing {((page || 1) - 1) * rowsPerPage} - {(page || 1) * rowsPerPage} of {totalElements}
111
+ </div>
112
+ </slot>
113
+ {/if}
114
+ <Paginator
115
+ bind:page
116
+ bind:maxPage
117
+ on:change={handlePaginationChange}
118
+ ></Paginator>
119
+ </slot>
123
120
  </div>
124
121
  </div>
125
122
 
126
123
  <style>
127
- .footer {
124
+ .paginated-table {
125
+ width: 100%;
128
126
  display: flex;
129
- justify-content: space-between;
130
- margin-top: 10px;
127
+ flex-direction: column;
128
+ gap: 24px;
129
+ align-items: center;
131
130
  }
132
131
 
133
- .loading-text {
134
- height: 200px;
135
- max-height: 100vh;
136
- display: flex;
137
- justify-content: center;
138
- align-items: center;
139
- color: var(--global-light-contrast-color);
140
- font-size: .9rem;
132
+ .header-sort-icon {
133
+ display: none;
134
+ }
135
+
136
+ .header-sort-icon.active {
137
+ display: inline;
141
138
  }
142
139
 
143
- .no-data {
144
- height: 200px;
145
- max-height: 100vh;
140
+ .range-descriptor {
141
+ font-size: .7rem;
142
+ }
143
+
144
+ .footer {
146
145
  display: flex;
147
- justify-content: center;
146
+ justify-content: space-between;
148
147
  align-items: center;
149
- color: var(--global-light-contrast-color);
150
- font-size: .9rem;
148
+ width: 100%;
151
149
  }
152
- </style> -->
150
+ </style>
@@ -1,10 +1,76 @@
1
1
  import { SvelteComponentTyped } from "svelte";
2
+ import SimpleTable from "../../simple/lists/SimpleTable.svelte";
3
+ import Paginator from "./Paginator.svelte";
4
+ import Dropdown from "../forms/Dropdown.svelte";
5
+ import { type ComponentProps } from "svelte";
6
+ type ArrayElement<ArrayType extends readonly unknown[]> = ArrayType extends readonly (infer ElementType)[] ? ElementType : never;
7
+ export type Header = ArrayElement<NonNullable<ComponentProps<SimpleTable>['headers']>>;
2
8
  declare const __propDef: {
3
- props: Record<string, never>;
9
+ props: {
10
+ class?: {
11
+ simpleTable?: ComponentProps<SimpleTable>['class'];
12
+ } | undefined;
13
+ headers?: ComponentProps<SimpleTable>['headers'];
14
+ items?: ComponentProps<SimpleTable>['items'];
15
+ sortedBy?: ComponentProps<SimpleTable>['sortedBy'];
16
+ sortDirection?: ComponentProps<SimpleTable>['sortDirection'];
17
+ page?: number | undefined;
18
+ maxPage?: ComponentProps<Paginator>['maxPage'];
19
+ rowsPerPageOptions?: ComponentProps<Dropdown>['items'];
20
+ hideRowsPerPage?: boolean | undefined;
21
+ totalElements?: number | undefined;
22
+ rowsPerPage?: number | undefined;
23
+ };
4
24
  events: {
25
+ sort: CustomEvent<{
26
+ sortedBy: string | undefined;
27
+ sortDirection: string;
28
+ }>;
29
+ } & {
5
30
  [evt: string]: CustomEvent<any>;
6
31
  };
7
- slots: {};
32
+ slots: {
33
+ header: {
34
+ head: import("../../simple/lists/SimpleTable.svelte").Header;
35
+ };
36
+ headerLabel: {};
37
+ custom: {
38
+ index: any;
39
+ columnIndex: any;
40
+ header: import("../../simple/lists/SimpleTable.svelte").Header;
41
+ item: {
42
+ [key: string]: any;
43
+ };
44
+ };
45
+ rowActions: {
46
+ index: any;
47
+ item: {
48
+ [key: string]: any;
49
+ };
50
+ };
51
+ append: {
52
+ index: any;
53
+ item: {
54
+ [key: string]: any;
55
+ };
56
+ };
57
+ footer: {
58
+ hideRowsPerPage: boolean;
59
+ rowsPerPageOptions: import("../forms/Dropdown.svelte").Item[] | undefined;
60
+ rowsPerPageSelection: import("../forms/Dropdown.svelte").Item[];
61
+ totalElements: number | undefined;
62
+ page: number;
63
+ maxPage: number | undefined;
64
+ rowsPerPage: number;
65
+ handlePaginationChange: () => void;
66
+ };
67
+ rangeDescriptor: {
68
+ page: number;
69
+ maxPage: number | undefined;
70
+ rowsPerPage: number;
71
+ totalElements: number | undefined;
72
+ };
73
+ };
8
74
  };
9
75
  export type PaginatedTableProps = typeof __propDef.props;
10
76
  export type PaginatedTableEvents = typeof __propDef.events;
@@ -47,7 +47,8 @@ $:
47
47
  icon="mdi-chevron-double-left"
48
48
  on:click={hardPrevious}
49
49
  --button-default-background-color="transparent"
50
- --button-default-focus-background-color="transparent"
50
+ --button-default-focus-background-color="rgb(var(--global-color-primary-500), .3)"
51
+ --button-default-focus-color="rgb(var(--global-color-contrast-900))"
51
52
  --button-default-hover-background-color="rgb(var(--global-color-primary-500))"
52
53
  --button-default-box-shadow="none"
53
54
  --button-default-color="rgb(var(--global-color-contrast-900))"
@@ -56,7 +57,8 @@ $:
56
57
  icon="mdi-chevron-left"
57
58
  on:click={previousPage}
58
59
  --button-default-background-color="transparent"
59
- --button-default-focus-background-color="transparent"
60
+ --button-default-focus-background-color="rgb(var(--global-color-primary-500), .3)"
61
+ --button-default-focus-color="rgb(var(--global-color-contrast-900))"
60
62
  --button-default-hover-background-color="rgb(var(--global-color-primary-500))"
61
63
  --button-default-box-shadow="none"
62
64
  --button-default-color="rgb(var(--global-color-contrast-900))"
@@ -65,7 +67,8 @@ $:
65
67
  <Button
66
68
  on:click={() => goToPage(page - 1)}
67
69
  --button-default-background-color="transparent"
68
- --button-default-focus-background-color="transparent"
70
+ --button-default-focus-background-color="rgb(var(--global-color-primary-500), .3)"
71
+ --button-default-focus-color="rgb(var(--global-color-contrast-900))"
69
72
  --button-default-hover-background-color="rgb(var(--global-color-primary-500))"
70
73
  --button-default-box-shadow="none"
71
74
  --button-default-color="rgb(var(--global-color-contrast-900))"
@@ -82,7 +85,8 @@ $:
82
85
  <Button
83
86
  on:click={() => goToPage(page + 1)}
84
87
  --button-default-background-color="transparent"
85
- --button-default-focus-background-color="transparent"
88
+ --button-default-focus-background-color="rgb(var(--global-color-primary-500), .3)"
89
+ --button-default-focus-color="rgb(var(--global-color-contrast-900))"
86
90
  --button-default-hover-background-color="rgb(var(--global-color-primary-500))"
87
91
  --button-default-box-shadow="none"
88
92
  --button-default-color="rgb(var(--global-color-contrast-900))"
@@ -93,7 +97,8 @@ $:
93
97
  on:click={nextPage}
94
98
  icon="mdi-chevron-right"
95
99
  --button-default-background-color="transparent"
96
- --button-default-focus-background-color="transparent"
100
+ --button-default-focus-background-color="rgb(var(--global-color-primary-500), .3)"
101
+ --button-default-focus-color="rgb(var(--global-color-contrast-900))"
97
102
  --button-default-hover-background-color="rgb(var(--global-color-primary-500))"
98
103
  --button-default-box-shadow="none"
99
104
  --button-default-color="rgb(var(--global-color-contrast-900))"
@@ -103,7 +108,8 @@ $:
103
108
  on:click={hardNext}
104
109
  icon="mdi-chevron-double-right"
105
110
  --button-default-background-color="transparent"
106
- --button-default-focus-background-color="transparent"
111
+ --button-default-focus-background-color="rgb(var(--global-color-primary-500), .3)"
112
+ --button-default-focus-color="rgb(var(--global-color-contrast-900))"
107
113
  --button-default-hover-background-color="rgb(var(--global-color-primary-500))"
108
114
  --button-default-box-shadow="none"
109
115
  --button-default-color="rgb(var(--global-color-contrast-900))"
File without changes
@@ -0,0 +1,97 @@
1
+ <script context="module"></script>
2
+
3
+ <script>import "./Filters.css";
4
+ import "../../../css/main.css";
5
+ import Drawer from "../../simple/navigation/Drawer.svelte";
6
+ import Menu from "../../simple/common/Menu.svelte";
7
+ import MediaQuery from "../../simple/common/MediaQuery.svelte";
8
+ import Button from "../../simple/buttons/Button.svelte";
9
+ import Icon from "../../simple/media/Icon.svelte";
10
+ import { createEventDispatcher } from "svelte";
11
+ import SelectableVerticalList from "../../simple/lists/SelectableVerticalList.svelte";
12
+ export let addFilterLabel = "Add filter", filters = [];
13
+ let dispatch = createEventDispatcher();
14
+ let open = false, activator;
15
+ function handleAddFilterClick() {
16
+ dispatch("addFilterClick");
17
+ open = true;
18
+ }
19
+ $:
20
+ filterOptions = filters.map((f) => {
21
+ return {
22
+ title: f.label,
23
+ name: f.name
24
+ };
25
+ });
26
+ let selected;
27
+ let focused;
28
+ $:
29
+ if (!!selected)
30
+ selected = void 0;
31
+ $:
32
+ if (!!focused && !open)
33
+ focused = void 0;
34
+ function handleFilterSelection() {
35
+ }
36
+ </script>
37
+
38
+
39
+ <div
40
+ class="add-filter-button"
41
+ bind:this={activator}
42
+ >
43
+ <Button
44
+ on:click={handleAddFilterClick}
45
+ >
46
+ <Icon name="mdi-plus"></Icon>
47
+ {addFilterLabel}
48
+ </Button>
49
+ </div>
50
+
51
+ <MediaQuery let:mAndDown>
52
+ {#if mAndDown}
53
+ <Drawer
54
+ bind:open={open}
55
+ position="bottom"
56
+ on:item-click
57
+ >
58
+ <SelectableVerticalList
59
+ bind:selected
60
+ bind:focused
61
+ bind:elements={filterOptions}
62
+ --selectable-vertical-list-default-width="100%"
63
+ --selectable-vertical-list-default-element-height="56px"
64
+ --selectable-vertical-list-default-title-font-size="null"
65
+ on:select={handleFilterSelection}
66
+ ></SelectableVerticalList>
67
+ </Drawer>
68
+ {:else}
69
+ <Menu
70
+ bind:activator={activator}
71
+ bind:open={open}
72
+ closeOnClickOutside
73
+ _boxShadow="rgb(var(--global-color-grey-900), .5) 0px 2px 4px"
74
+ _height="fit-content"
75
+ _maxHeight="300px"
76
+ _minWidth="100px"
77
+ _borderRadius="5px"
78
+ anchor="bottom-center"
79
+ >
80
+ <SelectableVerticalList
81
+ bind:selected
82
+ bind:focused
83
+ bind:elements={filterOptions}
84
+ --selectable-vertical-list-default-width="100%"
85
+ --selectable-vertical-list-default-element-height="56px"
86
+ --selectable-vertical-list-default-title-font-size="null"
87
+ on:select={handleFilterSelection}
88
+ ></SelectableVerticalList>
89
+ </Menu>
90
+ {/if}
91
+ </MediaQuery>
92
+
93
+ <style>
94
+ .add-filter-button {
95
+ width: fit-content;
96
+ }
97
+ </style>
@@ -0,0 +1,26 @@
1
+ import { SvelteComponentTyped } from "svelte";
2
+ export type ArrayElement<ArrayType extends readonly unknown[]> = ArrayType extends readonly (infer ElementType)[] ? ElementType : never;
3
+ import './Filters.css';
4
+ import '../../../css/main.css';
5
+ import type { Filter } from '../../../utils/filters/filters';
6
+ declare const __propDef: {
7
+ props: {
8
+ addFilterLabel?: string | undefined;
9
+ filters?: Filter[] | undefined;
10
+ };
11
+ events: {
12
+ 'item-click': CustomEvent<{
13
+ item: import("../../simple/navigation/Navigator.svelte").Item;
14
+ }>;
15
+ addFilterClick: CustomEvent<undefined>;
16
+ } & {
17
+ [evt: string]: CustomEvent<any>;
18
+ };
19
+ slots: {};
20
+ };
21
+ export type FiltersProps = typeof __propDef.props;
22
+ export type FiltersEvents = typeof __propDef.events;
23
+ export type FiltersSlots = typeof __propDef.slots;
24
+ export default class Filters extends SvelteComponentTyped<FiltersProps, FiltersEvents, FiltersSlots> {
25
+ }
26
+ export {};
@@ -14,6 +14,7 @@
14
14
  --button-default-text-hover-background-color: rgb(var(--global-color-primary-500), 0.2);
15
15
  --button-default-active-background-color: rgb(var(--global-color-primary-500));
16
16
  --button-default-focus-background-color: rgb(var(--global-color-primary-500));
17
+ --button-default-focus-color: rgb(var(--global-color-grey-50));
17
18
  --button-default-disabled-background-color: rgb(var(--global-color-primary-500), .6);
18
19
  --button-default-disabled-color: rgb(var(--global-color-grey-50), .6);
19
20
  --button-default-text-active-background-color: rgb(var(--global-color-primary-500), 0.4);
@@ -199,6 +199,10 @@ import CircularLoader from "../loaders/CircularLoader.svelte";
199
199
  --button-focus-background-color,
200
200
  var(--button-default-focus-background-color)
201
201
  );
202
+ color: var(
203
+ --button-focus-color,
204
+ var(--button-default-focus-color)
205
+ );
202
206
  }
203
207
 
204
208
  .button-text {
@@ -5,7 +5,7 @@ import "./Autocomplete.css";
5
5
  import { scrollInMenu } from "../common/scroller";
6
6
  let clazz = {};
7
7
  export { clazz as class };
8
- export let values = [], items, searchFunction = void 0, multiple = false, disabled = false, placeholder = "", width = "auto", height = "auto", maxWidth = void 0, openingId = "autocomplete-menu", searchText = void 0, maxVisibleChips = void 0, menuBoxShadow = "rgb(var(--global-color-background-300), .5) 0px 2px 4px", menuBorderRadius = "5px";
8
+ export let values = [], items, searchFunction = void 0, multiple = false, disabled = false, mandatory = false, placeholder = "", width = "auto", height = "auto", maxWidth = void 0, openingId = "autocomplete-menu", searchText = void 0, maxVisibleChips = void 0, menuBoxShadow = "rgb(var(--global-color-background-300), .5) 0px 2px 4px", menuBorderRadius = "5px";
9
9
  let dispatch = createEventDispatcher();
10
10
  function select(item) {
11
11
  const alreadyPresent = values.findIndex((i) => i.value === item.value) != -1;
@@ -23,6 +23,8 @@ function select(item) {
23
23
  }
24
24
  }
25
25
  function unselect(item) {
26
+ if (values.length == 1 && mandatory)
27
+ return;
26
28
  values = values.filter((i) => i.value != item.value);
27
29
  refreshMenuWidth();
28
30
  dispatch("change", {
@@ -32,6 +34,8 @@ function unselect(item) {
32
34
  });
33
35
  }
34
36
  function pop() {
37
+ if (values.length == 1 && mandatory)
38
+ return;
35
39
  let poppedElement = values.pop();
36
40
  values = [...values];
37
41
  refreshMenuWidth();
@@ -17,6 +17,7 @@ declare const __propDef: {
17
17
  searchFunction?: ((item: Item, searchText: string | undefined) => boolean) | undefined;
18
18
  multiple?: boolean | undefined;
19
19
  disabled?: boolean | undefined;
20
+ mandatory?: boolean | undefined;
20
21
  placeholder?: string | undefined;
21
22
  width?: string | undefined;
22
23
  height?: string | undefined;
@@ -2,7 +2,6 @@
2
2
 
3
3
  <script>import "../../../css/main.css";
4
4
  import "./SimpleTable.css";
5
- import { dateToString } from "../dates/utils";
6
5
  import Icon from "../media/Icon.svelte";
7
6
  import { createEventDispatcher } from "svelte";
8
7
  let clazz = {};
@@ -25,6 +24,9 @@ function handleHeaderClick(header) {
25
24
  sortDirection
26
25
  });
27
26
  }
27
+ function formatDate(dateTime, dateFormat) {
28
+ return dateTime.setLocale(dateFormat.locale).toFormat(dateFormat.format);
29
+ }
28
30
  </script>
29
31
 
30
32
  {#if !!items && Array.isArray(items)}
@@ -33,8 +35,8 @@ function handleHeaderClick(header) {
33
35
  <thead class="thead {clazz.header || ''}">
34
36
  <tr>
35
37
  {#each headers as head}
36
- <th
37
- style:width={head.width}
38
+ <th
39
+ style:width={head.width}
38
40
  style:min-width={head.minWidth}
39
41
  class:sortable={head.sortable}
40
42
  on:click={() => handleHeaderClick(head)}
@@ -46,16 +48,16 @@ function handleHeaderClick(header) {
46
48
  </slot>
47
49
  </span>
48
50
  {#if head.sortable}
49
- <span
51
+ <span
50
52
  class="header-sort-icon"
51
53
  class:active={sortedBy == head.value}
52
- class:asc={sortDirection == 'asc'}
53
- class:desc={sortDirection == 'desc'}
54
+ class:asc={sortDirection == "asc"}
55
+ class:desc={sortDirection == "desc"}
54
56
  >
55
- {#if sortDirection == 'asc'}
56
- <Icon name="mdi-arrow-up"></Icon>
57
+ {#if sortDirection == "asc"}
58
+ <Icon name="mdi-arrow-up" />
57
59
  {:else}
58
- <Icon name="mdi-arrow-down"></Icon>
60
+ <Icon name="mdi-arrow-down" />
59
61
  {/if}
60
62
  </span>
61
63
  {/if}
@@ -74,7 +76,7 @@ function handleHeaderClick(header) {
74
76
  <tr class="item-tr {clazz.row || ''}">
75
77
  {#each headers as header, j}
76
78
  <td class="{clazz.cell || ''}">
77
- {#if header.type == "custom"}
79
+ {#if header.type.key == "custom"}
78
80
  <slot
79
81
  name="custom"
80
82
  index={i}
@@ -82,9 +84,15 @@ function handleHeaderClick(header) {
82
84
  {header}
83
85
  {item}
84
86
  />
85
- {:else if header.type == "date"}
86
- {dateToString(item[header.value], "dayAndHours", "it")}
87
- {:else}
87
+ {:else if header.type.key == "date"}
88
+ {formatDate(item[header.value], header.type.params)}
89
+ {:else if header.type.key == "icon"}
90
+ <Icon
91
+ --icon-color={header.type.params?.color }
92
+ --icon-size={header.type.params?.size}
93
+ name={header.type.params?.name || ''}
94
+ />
95
+ {:else}
88
96
  {item[header.value]}
89
97
  {/if}
90
98
  </td>
@@ -104,10 +112,7 @@ function handleHeaderClick(header) {
104
112
 
105
113
  <style>
106
114
  .simple-table-container {
107
- width: var(
108
- --simple-table-width,
109
- var(--simple-table-default-width)
110
- );
115
+ width: var(--simple-table-width, var(--simple-table-default-width));
111
116
  min-width: var(
112
117
  --simple-table-min-width,
113
118
  var(--simple-table-default-min-width)
@@ -116,10 +121,7 @@ function handleHeaderClick(header) {
116
121
  --simple-table-max-width,
117
122
  var(--simple-table-default-max-width)
118
123
  );
119
- height: var(
120
- --simple-table-height,
121
- var(--simple-table-default-height)
122
- );
124
+ height: var(--simple-table-height, var(--simple-table-default-height));
123
125
  min-height: var(
124
126
  --simple-table-min-height,
125
127
  var(--simple-table-default-min-height)
@@ -158,7 +160,7 @@ function handleHeaderClick(header) {
158
160
 
159
161
  .thead th.sortable {
160
162
  cursor: pointer;
161
- transition: all .1s ease-in;
163
+ transition: all 0.1s ease-in;
162
164
  user-select: none;
163
165
  }
164
166
 
@@ -221,7 +223,7 @@ function handleHeaderClick(header) {
221
223
  --simple-table-row-height,
222
224
  var(--simple-table-default-row-height)
223
225
  );
224
- transition: background-color .1s ease-in-out;
226
+ transition: background-color 0.1s ease-in-out;
225
227
  }
226
228
 
227
229
  .item-tr:hover {
@@ -1,8 +1,9 @@
1
1
  import { SvelteComponentTyped } from "svelte";
2
+ export type HeaderType = ColumnBoolean | ColumnString | ColumnNumber | ColumnDate | ColumnIcon | ColumnCheckBox | ColumnCostom;
2
3
  export type Header = {
3
4
  value: string;
4
5
  label: string;
5
- type: "boolean" | "string" | "number" | "date" | "custom";
6
+ type: HeaderType;
6
7
  width?: string;
7
8
  minWidth?: string;
8
9
  sortable?: boolean;
@@ -12,6 +13,7 @@ export type Header = {
12
13
  };
13
14
  import '../../../css/main.css';
14
15
  import './SimpleTable.css';
16
+ import type { ColumnBoolean, ColumnCheckBox, ColumnCostom, ColumnDate, ColumnIcon, ColumnNumber, ColumnString } from './columnTypes';
15
17
  declare const __propDef: {
16
18
  props: {
17
19
  class?: {
@@ -0,0 +1,35 @@
1
+ export type ColumnDate = {
2
+ key: "date";
3
+ params: {
4
+ format: string;
5
+ locale: string;
6
+ };
7
+ };
8
+ export type ColumnIcon = {
9
+ key: "icon";
10
+ params: {
11
+ name: string;
12
+ color: string;
13
+ size: string;
14
+ };
15
+ };
16
+ export type ColumnBoolean = {
17
+ key: "boolean";
18
+ params?: {};
19
+ };
20
+ export type ColumnString = {
21
+ key: "string";
22
+ params?: {};
23
+ };
24
+ export type ColumnNumber = {
25
+ key: "number";
26
+ params?: {};
27
+ };
28
+ export type ColumnCostom = {
29
+ key: "custom";
30
+ params?: {};
31
+ };
32
+ export type ColumnCheckBox = {
33
+ key: "checkbox";
34
+ params?: {};
35
+ };
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.d.ts CHANGED
@@ -46,6 +46,7 @@ export { default as ProgressBar } from './components/simple/progress/ProgressBar
46
46
  export { default as ProductCard } from './components/composed/shop/ProductCard.svelte';
47
47
  export { default as ProductsGrid } from './components/composed/shop/ProductsGrid.svelte';
48
48
  export { default as PaginatedTable } from './components/composed/list/PaginatedTable.svelte';
49
+ export { default as Filters } from './components/composed/search/Filters.svelte';
49
50
  export { default as mediaQuery } from './stores/mediaQuery';
50
51
  export { default as theme, toggleTheme, setTheme } from './stores/theme';
51
52
  export { default as SimpleTimeLine } from './components/simple/timeline/SimpleTimeLine.svelte';
package/dist/index.js CHANGED
@@ -46,6 +46,7 @@ export { default as ProgressBar } from './components/simple/progress/ProgressBar
46
46
  export { default as ProductCard } from './components/composed/shop/ProductCard.svelte';
47
47
  export { default as ProductsGrid } from './components/composed/shop/ProductsGrid.svelte';
48
48
  export { default as PaginatedTable } from './components/composed/list/PaginatedTable.svelte';
49
+ export { default as Filters } from './components/composed/search/Filters.svelte';
49
50
  export { default as mediaQuery } from './stores/mediaQuery';
50
51
  export { default as theme, toggleTheme, setTheme } from './stores/theme';
51
52
  export { default as SimpleTimeLine } from './components/simple/timeline/SimpleTimeLine.svelte';
@@ -0,0 +1,43 @@
1
+ import type { JoinModifier } from "./modifiers/join";
2
+ import type { WhereModifier } from "./modifiers/where";
3
+ export type Modifier = WhereModifier | JoinModifier;
4
+ export type JsonQuery = {
5
+ modifiers: Modifier[];
6
+ };
7
+ export default class Builder {
8
+ private modifiers;
9
+ constructor();
10
+ where(callback: (builder: Builder) => void): Builder;
11
+ where(key: Record<string, string | number | Date>): Builder;
12
+ where(key: string, value: string | number | Date): Builder;
13
+ where(key: string, operator: string, value: string | number | Date): Builder;
14
+ whereNot(callback: (builder: Builder) => void): Builder;
15
+ whereNot(key: Record<string, string | number | Date>): Builder;
16
+ whereNot(key: string, value: string | number | Date): Builder;
17
+ whereNot(key: string, operator: string, value: string | number | Date): Builder;
18
+ orWhere(callback: (builder: Builder) => void): Builder;
19
+ orWhere(key: Record<string, string | number | Date>): Builder;
20
+ orWhere(key: string, value: string | number | Date): Builder;
21
+ orWhere(key: string, operator: string, value: string | number | Date): Builder;
22
+ orWhereNot(callback: (builder: Builder) => void): Builder;
23
+ orWhereNot(key: Record<string, string | number | Date>): Builder;
24
+ orWhereNot(key: string, value: string | number | Date): Builder;
25
+ orWhereNot(key: string, operator: string, value: string | number | Date): Builder;
26
+ private applyWhereClause;
27
+ join(table: string, onCallback: (onBuilder: OnClauseBuilder) => void): this;
28
+ leftJoin(table: string, onCallback: (onBuilder: OnClauseBuilder) => void): this;
29
+ rightJoin(table: string, onCallback: (onBuilder: OnClauseBuilder) => void): this;
30
+ private applyJoinClause;
31
+ toJson(): JsonQuery;
32
+ }
33
+ import type { JoinModifierOnClause } from "./modifiers/join";
34
+ declare class OnClauseBuilder {
35
+ private onClauses;
36
+ constructor();
37
+ get json(): JoinModifierOnClause[];
38
+ on(from: string, to: string): void;
39
+ on(from: string, operator: string, to: string): void;
40
+ orOn(from: string, to: string): void;
41
+ orOn(from: string, operator: string, to: string): void;
42
+ }
43
+ export {};
@@ -0,0 +1,137 @@
1
+ export default class Builder {
2
+ modifiers = [];
3
+ constructor() {
4
+ this.modifiers = [];
5
+ }
6
+ where(first, second, third) {
7
+ return this.applyWhereClause('and', first, second, third);
8
+ }
9
+ whereNot(first, second, third) {
10
+ return this.applyWhereClause('and', first, second, third);
11
+ }
12
+ orWhere(first, second, third) {
13
+ return this.applyWhereClause('or', first, second, third);
14
+ }
15
+ orWhereNot(first, second, third) {
16
+ return this.applyWhereClause('orNot', first, second, third);
17
+ }
18
+ applyWhereClause(logicalOperator, first, second, third) {
19
+ if (!!third) {
20
+ if (!!second && typeof first == 'string' && typeof second == 'string') {
21
+ this.modifiers.push({
22
+ method: 'where',
23
+ kind: 'simple',
24
+ key: first,
25
+ operator: second,
26
+ value: third,
27
+ logicalOperator: logicalOperator
28
+ });
29
+ }
30
+ else if (typeof first == 'object') {
31
+ this.modifiers.push({
32
+ method: 'where',
33
+ kind: 'object',
34
+ values: first,
35
+ logicalOperator
36
+ });
37
+ }
38
+ }
39
+ else if (typeof first == 'string' && !!second) {
40
+ this.modifiers.push({
41
+ method: 'where',
42
+ kind: 'simple',
43
+ key: first,
44
+ value: second,
45
+ logicalOperator
46
+ });
47
+ }
48
+ else if (typeof first == 'function') {
49
+ let builder = new Builder();
50
+ first(builder);
51
+ if (!builder.modifiers.every(el => el.method == 'where'))
52
+ throw new Error('inconsistent json query from where callback');
53
+ this.modifiers.push({
54
+ method: 'where',
55
+ kind: 'grouped',
56
+ logicalOperator,
57
+ children: builder.modifiers.filter((el) => el.method == 'where')
58
+ });
59
+ }
60
+ return this;
61
+ }
62
+ join(table, onCallback) {
63
+ let onBuilder = new OnClauseBuilder();
64
+ onCallback(onBuilder);
65
+ this.applyJoinClause('inner', table, onBuilder.json);
66
+ return this;
67
+ }
68
+ leftJoin(table, onCallback) {
69
+ let onBuilder = new OnClauseBuilder();
70
+ onCallback(onBuilder);
71
+ this.applyJoinClause('left', table, onBuilder.json);
72
+ return this;
73
+ }
74
+ rightJoin(table, onCallback) {
75
+ let onBuilder = new OnClauseBuilder();
76
+ onCallback(onBuilder);
77
+ this.applyJoinClause('right', table, onBuilder.json);
78
+ return this;
79
+ }
80
+ applyJoinClause(kind, table, on) {
81
+ this.modifiers.push({
82
+ method: 'join',
83
+ kind: kind,
84
+ on: on,
85
+ table: table
86
+ });
87
+ return this;
88
+ }
89
+ toJson() {
90
+ return {
91
+ modifiers: this.modifiers
92
+ };
93
+ }
94
+ }
95
+ class OnClauseBuilder {
96
+ onClauses;
97
+ constructor() {
98
+ this.onClauses = [];
99
+ }
100
+ get json() {
101
+ return this.onClauses;
102
+ }
103
+ on(first, second, third) {
104
+ if (!third) {
105
+ this.onClauses.push({
106
+ from: first,
107
+ operator: '=',
108
+ to: second
109
+ });
110
+ }
111
+ else {
112
+ this.onClauses.push({
113
+ from: first,
114
+ operator: second,
115
+ to: third
116
+ });
117
+ }
118
+ }
119
+ orOn(first, second, third) {
120
+ if (!third) {
121
+ this.onClauses.push({
122
+ from: first,
123
+ operator: '=',
124
+ to: second,
125
+ logicalOperator: 'or'
126
+ });
127
+ }
128
+ else {
129
+ this.onClauses.push({
130
+ from: first,
131
+ operator: second,
132
+ to: third,
133
+ logicalOperator: 'or'
134
+ });
135
+ }
136
+ }
137
+ }
@@ -0,0 +1,26 @@
1
+ import Builder from "./builder";
2
+ type MultiStringFilter = {
3
+ type: 'multiString';
4
+ columns: string[];
5
+ operator?: 'or' | 'and';
6
+ };
7
+ type StringFilter = {
8
+ type: 'string';
9
+ column: string;
10
+ value: string | undefined;
11
+ mode?: 'equal' | 'like' | 'ilike';
12
+ };
13
+ export type Filter = {
14
+ name: string;
15
+ active: boolean;
16
+ hidden?: boolean;
17
+ label: string;
18
+ } & (StringFilter | MultiStringFilter);
19
+ export default class Converter {
20
+ constructor();
21
+ createBuilder(params: {
22
+ filters: Filter[];
23
+ }): Builder;
24
+ private applyStringFilter;
25
+ }
26
+ export {};
@@ -0,0 +1,29 @@
1
+ import Builder from "./builder";
2
+ export default class Converter {
3
+ constructor() {
4
+ }
5
+ createBuilder(params) {
6
+ let builder = new Builder();
7
+ for (let i = 0; i < params.filters.length; i += 1) {
8
+ const filter = params.filters[i];
9
+ if (filter.type == 'string') {
10
+ this.applyStringFilter({ builder, filter });
11
+ }
12
+ }
13
+ return builder;
14
+ }
15
+ applyStringFilter(params) {
16
+ if (params.filter.value === undefined)
17
+ return params.builder;
18
+ if (params.filter.mode == 'like') {
19
+ params.builder.where(params.filter.column, 'like', params.filter.value);
20
+ }
21
+ else if (params.filter.mode == 'ilike') {
22
+ params.builder.where(params.filter.column, 'ilike', params.filter.value);
23
+ }
24
+ else {
25
+ params.builder.where(params.filter.column, '=', params.filter.value);
26
+ }
27
+ return params.builder;
28
+ }
29
+ }
@@ -0,0 +1,26 @@
1
+ export type JoinModifierOnClause = {
2
+ from: string;
3
+ operator: string;
4
+ to: string;
5
+ logicalOperator?: 'and' | 'or';
6
+ };
7
+ type RightJoinModifier = {
8
+ method: 'join';
9
+ kind: 'right';
10
+ table: string;
11
+ on: JoinModifierOnClause[];
12
+ };
13
+ type InnerJoinModifier = {
14
+ method: 'join';
15
+ kind: 'inner';
16
+ table: string;
17
+ on: JoinModifierOnClause[];
18
+ };
19
+ type LeftJoinJsonModifier = {
20
+ method: 'join';
21
+ kind: 'left';
22
+ table: string;
23
+ on: JoinModifierOnClause[];
24
+ };
25
+ export type JoinModifier = LeftJoinJsonModifier | InnerJoinModifier | RightJoinModifier;
26
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,29 @@
1
+ type GroupedWhere = {
2
+ method: 'where';
3
+ kind: 'grouped';
4
+ logicalOperator?: 'and' | 'or' | 'andNot' | 'orNot';
5
+ children: (ObjectWhere | SimpleWhere | GroupedWhere | InWhere)[];
6
+ };
7
+ type ObjectWhere = {
8
+ method: 'where';
9
+ kind: 'object';
10
+ logicalOperator?: 'and' | 'or' | 'andNot' | 'orNot';
11
+ values: Record<string, string | number | Date>;
12
+ };
13
+ type SimpleWhere = {
14
+ method: 'where';
15
+ kind: 'simple';
16
+ logicalOperator?: 'and' | 'or' | 'andNot' | 'orNot';
17
+ key: string;
18
+ operator?: string;
19
+ value: string | number | Date;
20
+ };
21
+ type InWhere = {
22
+ method: 'where';
23
+ kind: 'in';
24
+ logicalOperator?: 'and' | 'or' | 'andNot' | 'orNot';
25
+ key: string;
26
+ value: (string | number | Date)[];
27
+ };
28
+ export type WhereModifier = SimpleWhere | ObjectWhere | GroupedWhere | InWhere;
29
+ export {};
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@likable-hair/svelte",
3
3
  "description": "A Svelte component for likablehair",
4
- "version": "3.0.19",
4
+ "version": "3.0.20",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
7
7
  "build": "vite build && npm run package",