@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inglorious/ui",
3
- "version": "9.11.0",
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.0"
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.0",
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",
@@ -124,7 +124,7 @@
124
124
  user-select: none;
125
125
  padding: var(--iw-space-2) var(--iw-space-3);
126
126
 
127
- &:focused {
127
+ &:focus-visible {
128
128
  background-color: var(--iw-color-bg-secondary);
129
129
  }
130
130
 
@@ -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
- <div
121
- @click=${() => column.isSortable && props.onSortChange?.(column.id)}
122
- class="iw-data-grid-header-title"
123
- >
124
- ${column.title}
125
- ${when(column.isSortable, () =>
126
- getSortIcon(getSortDirection(props, column.id)),
127
- )}
128
- </div>
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: { value: string; placeholder?: string } | null
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, api: Api): TemplateResult
170
- renderHeader(entity: DataGridProps, api: Api): TemplateResult
171
- renderToolbar(entity: DataGridProps, api: Api): TemplateResult
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, api: Api): TemplateResult
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