@inglorious/ui 9.11.0 → 9.11.1
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/package.json +3 -3
- package/src/controls/select/style.css +1 -1
- package/src/data-display/data-grid/filters/helpers.js +24 -0
- package/src/data-display/data-grid/filters/input.js +3 -1
- package/src/data-display/data-grid/filters/range.js +11 -1
- package/src/data-display/data-grid/filters/select.js +2 -0
- package/src/data-display/data-grid/template.js +17 -10
- package/src/data-display/data-grid/theme.css +16 -0
- package/types/data-display/data-grid.d.ts +27 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inglorious/ui",
|
|
3
|
-
"version": "9.11.
|
|
3
|
+
"version": "9.11.1",
|
|
4
4
|
"description": "A design system for Inglorious Web with render-function components and customizable themes",
|
|
5
5
|
"author": "Matteo Antony Mistretta <antony.mistretta@gmail.com> (https://ingloriouscoderz.it)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -341,7 +341,7 @@
|
|
|
341
341
|
"peerDependencies": {
|
|
342
342
|
"@inglorious/store": "^12.1.1",
|
|
343
343
|
"@inglorious/utils": "^5.1.0",
|
|
344
|
-
"@inglorious/web": "^6.14.
|
|
344
|
+
"@inglorious/web": "^6.14.1"
|
|
345
345
|
},
|
|
346
346
|
"devDependencies": {
|
|
347
347
|
"@iconify-icons/fa7-brands": "^2.0.0",
|
|
@@ -353,7 +353,7 @@
|
|
|
353
353
|
"@inglorious/store": "12.1.1",
|
|
354
354
|
"@inglorious/vite-plugin-jsx": "2.0.6",
|
|
355
355
|
"@inglorious/vite-plugin-vue": "1.0.7",
|
|
356
|
-
"@inglorious/web": "6.14.
|
|
356
|
+
"@inglorious/web": "6.14.1",
|
|
357
357
|
"@lit-labs/ssr": "^4.1.0",
|
|
358
358
|
"@storybook/addon-docs": "^10.6.5",
|
|
359
359
|
"@storybook/web-components-vite": "^10.6.5",
|
|
@@ -6,3 +6,27 @@ export function format(value, type) {
|
|
|
6
6
|
return new Date(value).getTime()
|
|
7
7
|
return value
|
|
8
8
|
}
|
|
9
|
+
|
|
10
|
+
const DATE_LENGTH = 10
|
|
11
|
+
const DATETIME_LENGTH = 16
|
|
12
|
+
const MINUTE_MS = 60_000
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A filter value as its field shows it. Date fields read their text as UTC,
|
|
16
|
+
* datetime fields as local time, so each turns back the same way.
|
|
17
|
+
* @param {any} value
|
|
18
|
+
* @param {string} inputType
|
|
19
|
+
* @returns {string|number}
|
|
20
|
+
*/
|
|
21
|
+
export function toField(value, inputType) {
|
|
22
|
+
if (value == null || Number.isNaN(value)) return ""
|
|
23
|
+
if (typeof value !== "number") return value
|
|
24
|
+
if (inputType === "date") {
|
|
25
|
+
return new Date(value).toISOString().slice(0, DATE_LENGTH)
|
|
26
|
+
}
|
|
27
|
+
if (inputType === "datetime-local") {
|
|
28
|
+
const offset = new Date(value).getTimezoneOffset() * MINUTE_MS
|
|
29
|
+
return new Date(value - offset).toISOString().slice(0, DATETIME_LENGTH)
|
|
30
|
+
}
|
|
31
|
+
return value
|
|
32
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Input } from "../../../controls/input/index.js"
|
|
2
|
-
import { format } from "./helpers.js"
|
|
2
|
+
import { format, toField } from "./helpers.js"
|
|
3
3
|
|
|
4
4
|
const DEFAULT_PLACEHOLDER = {
|
|
5
5
|
number: "=",
|
|
@@ -10,7 +10,9 @@ export const InputFilter = {
|
|
|
10
10
|
render(entity, column) {
|
|
11
11
|
return Input.render({
|
|
12
12
|
name: column.id,
|
|
13
|
+
ariaLabel: column.filter.ariaLabel ?? `Filter ${column.title}`,
|
|
13
14
|
inputType: column.filter.type,
|
|
15
|
+
value: toField(entity.filters[column.id], column.filter.type),
|
|
14
16
|
placeholder:
|
|
15
17
|
column.filter.placeholder ?? DEFAULT_PLACEHOLDER[column.filter.type],
|
|
16
18
|
size: "sm",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { html } from "@inglorious/web"
|
|
2
2
|
|
|
3
3
|
import { Input } from "../../../controls/input/index.js"
|
|
4
|
-
import { format } from "./helpers.js"
|
|
4
|
+
import { format, toField } from "./helpers.js"
|
|
5
5
|
|
|
6
6
|
const RANGE_TYPE = {
|
|
7
7
|
range: "number",
|
|
@@ -15,7 +15,12 @@ export const RangeFilter = {
|
|
|
15
15
|
return html`<div class="iw-data-grid-filter-range">
|
|
16
16
|
${Input.render({
|
|
17
17
|
name: `${column.id}Min`,
|
|
18
|
+
ariaLabel: column.filter.minLabel ?? `Filter ${column.title}: min`,
|
|
18
19
|
inputType: RANGE_TYPE[column.filter.type],
|
|
20
|
+
value: toField(
|
|
21
|
+
entity.filters[column.id]?.min,
|
|
22
|
+
RANGE_TYPE[column.filter.type],
|
|
23
|
+
),
|
|
19
24
|
placeholder: column.filter.placeholder ?? "≥",
|
|
20
25
|
size: "sm",
|
|
21
26
|
isFullWidth: true,
|
|
@@ -29,7 +34,12 @@ export const RangeFilter = {
|
|
|
29
34
|
})}
|
|
30
35
|
${Input.render({
|
|
31
36
|
name: `${column.id}Max`,
|
|
37
|
+
ariaLabel: column.filter.maxLabel ?? `Filter ${column.title}: max`,
|
|
32
38
|
inputType: RANGE_TYPE[column.filter.type],
|
|
39
|
+
value: toField(
|
|
40
|
+
entity.filters[column.id]?.max,
|
|
41
|
+
RANGE_TYPE[column.filter.type],
|
|
42
|
+
),
|
|
33
43
|
placeholder: column.filter.placeholder ?? "≤",
|
|
34
44
|
size: "sm",
|
|
35
45
|
isFullWidth: true,
|
|
@@ -5,6 +5,8 @@ export const SelectFilter = {
|
|
|
5
5
|
render(entity, column) {
|
|
6
6
|
return Select.render({
|
|
7
7
|
name: column.id,
|
|
8
|
+
ariaLabel: column.filter.ariaLabel ?? `Filter ${column.title}`,
|
|
9
|
+
value: entity.filters[column.id] ?? "",
|
|
8
10
|
size: "sm",
|
|
9
11
|
isFullWidth: true,
|
|
10
12
|
options: column.filter.options,
|
|
@@ -117,16 +117,22 @@ export const DataGrid = {
|
|
|
117
117
|
class="iw-data-grid-header-column"
|
|
118
118
|
style=${getColumnStyle(column)}
|
|
119
119
|
>
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
120
|
+
${when(
|
|
121
|
+
column.isSortable,
|
|
122
|
+
() =>
|
|
123
|
+
html`<button
|
|
124
|
+
type="button"
|
|
125
|
+
class="iw-data-grid-header-title iw-data-grid-header-sort"
|
|
126
|
+
@click=${() => props.onSortChange?.(column.id)}
|
|
127
|
+
>
|
|
128
|
+
${column.title}
|
|
129
|
+
<span aria-hidden="true"
|
|
130
|
+
>${getSortIcon(getSortDirection(props, column.id))}</span
|
|
131
|
+
>
|
|
132
|
+
</button>`,
|
|
133
|
+
() =>
|
|
134
|
+
html`<div class="iw-data-grid-header-title">${column.title}</div>`,
|
|
135
|
+
)}
|
|
130
136
|
${when(column.isFilterable, () => Filters.render(props, column))}
|
|
131
137
|
|
|
132
138
|
<div
|
|
@@ -153,6 +159,7 @@ export const DataGrid = {
|
|
|
153
159
|
size: "sm",
|
|
154
160
|
isFullWidth: true,
|
|
155
161
|
name: "search",
|
|
162
|
+
ariaLabel: props.search.ariaLabel ?? "Search",
|
|
156
163
|
inputType: "text",
|
|
157
164
|
placeholder: props.search.placeholder ?? "Fuzzy search...",
|
|
158
165
|
value: props.search.value,
|
|
@@ -29,6 +29,22 @@
|
|
|
29
29
|
white-space: nowrap;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
.iw-data-grid-header-sort {
|
|
33
|
+
padding: 0;
|
|
34
|
+
border: 0;
|
|
35
|
+
background: none;
|
|
36
|
+
color: inherit;
|
|
37
|
+
font: inherit;
|
|
38
|
+
font-weight: var(--iw-font-weight-bold);
|
|
39
|
+
text-align: start;
|
|
40
|
+
cursor: pointer;
|
|
41
|
+
|
|
42
|
+
&:focus-visible {
|
|
43
|
+
outline: 2px solid var(--iw-color-primary);
|
|
44
|
+
outline-offset: 2px;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
32
48
|
.iw-data-grid-column-resizer {
|
|
33
49
|
&::after {
|
|
34
50
|
content: "";
|
|
@@ -36,6 +36,12 @@ export interface Column {
|
|
|
36
36
|
filter?: {
|
|
37
37
|
type: "text" | "number" | "range" | "select" | "date" | "time" | "datetime"
|
|
38
38
|
options?: SelectOption[]
|
|
39
|
+
/** The filter field's accessible name. Defaults to "Filter <title>". */
|
|
40
|
+
ariaLabel?: string
|
|
41
|
+
/** A range filter's lower field's accessible name. */
|
|
42
|
+
minLabel?: string
|
|
43
|
+
/** A range filter's upper field's accessible name. */
|
|
44
|
+
maxLabel?: string
|
|
39
45
|
[key: string]: any
|
|
40
46
|
}
|
|
41
47
|
/**
|
|
@@ -67,7 +73,12 @@ export interface DataGridProps<T extends Row = Row> {
|
|
|
67
73
|
columns: Column[]
|
|
68
74
|
sorts: { column: string; direction: "asc" | "desc" }[]
|
|
69
75
|
filters: Record<string, any>
|
|
70
|
-
search: {
|
|
76
|
+
search: {
|
|
77
|
+
value: string
|
|
78
|
+
placeholder?: string
|
|
79
|
+
/** The search field's accessible name. Defaults to "Search". */
|
|
80
|
+
ariaLabel?: string
|
|
81
|
+
} | null
|
|
71
82
|
isStriped?: boolean
|
|
72
83
|
isVirtualized?: boolean
|
|
73
84
|
virtualization?: DataGridVirtualization
|
|
@@ -166,36 +177,41 @@ export type DataGridType = {
|
|
|
166
177
|
virtualMount(entity: DataGridProps, containerEl: HTMLElement): void
|
|
167
178
|
virtualScroll(entity: DataGridProps, containerEl: HTMLElement): void
|
|
168
179
|
render(entity: DataGridProps, api: Api): TemplateResult
|
|
169
|
-
renderDataGrid(entity: DataGridProps
|
|
170
|
-
renderHeader(entity: DataGridProps
|
|
171
|
-
renderToolbar(entity: DataGridProps
|
|
180
|
+
renderDataGrid(entity: DataGridProps): TemplateResult
|
|
181
|
+
renderHeader(entity: DataGridProps): TemplateResult
|
|
182
|
+
renderToolbar(entity: DataGridProps): TemplateResult
|
|
183
|
+
renderSearchbar(entity: DataGridProps): TemplateResult
|
|
172
184
|
renderHeaderColumn(
|
|
173
185
|
entity: DataGridProps,
|
|
174
186
|
payload: { column: Column; index: number },
|
|
175
|
-
api: Api,
|
|
176
187
|
): TemplateResult
|
|
177
|
-
renderBody(entity: DataGridProps
|
|
188
|
+
renderBody(entity: DataGridProps): TemplateResult
|
|
178
189
|
renderRow(
|
|
179
190
|
entity: DataGridProps,
|
|
180
191
|
payload: { row: Row; index: number },
|
|
181
|
-
api: Api,
|
|
182
192
|
): TemplateResult
|
|
183
193
|
renderCell(
|
|
184
194
|
entity: DataGridProps,
|
|
185
195
|
payload: { cell: any; index: number; row?: Row },
|
|
186
|
-
api: Api,
|
|
187
196
|
): TemplateResult
|
|
188
197
|
renderEditor(
|
|
189
198
|
entity: DataGridProps,
|
|
190
199
|
payload: { value: any; column: Column; row: Row; index: number },
|
|
191
|
-
api: Api,
|
|
192
200
|
): TemplateResult
|
|
193
|
-
renderEdits(entity: DataGridProps, editCount: number): TemplateResult
|
|
194
201
|
renderValue(
|
|
195
202
|
entity: DataGridProps,
|
|
196
203
|
payload: { value: any; column: Column; index: number },
|
|
197
|
-
api: Api,
|
|
198
204
|
): any
|
|
205
|
+
renderFooter(entity: DataGridProps): TemplateResult
|
|
206
|
+
renderEdits(entity: DataGridProps, editCount: number): TemplateResult
|
|
207
|
+
renderPagination(
|
|
208
|
+
entity: DataGridProps,
|
|
209
|
+
pagination: DataGridPaginationInfo,
|
|
210
|
+
): TemplateResult
|
|
211
|
+
renderPageSize(
|
|
212
|
+
entity: DataGridProps,
|
|
213
|
+
pagination: DataGridPaginationInfo,
|
|
214
|
+
): TemplateResult
|
|
199
215
|
}
|
|
200
216
|
|
|
201
217
|
export declare const DataGrid: DataGridType
|