@norconsult-digital-public/isypixel 2.0.2 → 2.0.4-canary.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/LICENSE.md +11 -0
- package/dist/docs/web-components/ip-avatar/llm.md +176 -0
- package/dist/docs/web-components/ip-avatar-stack/llm.md +171 -0
- package/dist/{web-components/components → docs/web-components}/ip-button/llm.md +17 -10
- package/dist/docs/web-components/ip-card/llm.md +209 -0
- package/dist/docs/web-components/ip-chip/llm.md +157 -0
- package/dist/docs/web-components/ip-chip-group/llm.md +165 -0
- package/dist/docs/web-components/ip-date-display/llm.md +161 -0
- package/dist/docs/web-components/ip-exp-data-grid/llm.md +598 -0
- package/dist/docs/web-components/ip-exp-data-grid-action/llm.md +193 -0
- package/dist/docs/web-components/ip-exp-data-grid-card/llm.md +133 -0
- package/dist/docs/web-components/ip-exp-data-grid-column/llm.md +178 -0
- package/dist/docs/web-components/ip-exp-data-grid-column-group/llm.md +181 -0
- package/dist/docs/web-components/ip-exp-date-picker/llm.md +287 -0
- package/dist/docs/web-components/ip-exp-dialog/llm.md +188 -0
- package/dist/docs/web-components/ip-exp-dropdown-menu/llm.md +232 -0
- package/dist/docs/web-components/ip-exp-dropdown-menu-item/llm.md +177 -0
- package/dist/docs/web-components/ip-exp-filter-builder/llm.md +212 -0
- package/dist/docs/web-components/ip-exp-split-button/llm.md +211 -0
- package/dist/docs/web-components/ip-exp-switch/llm.md +143 -0
- package/dist/docs/web-components/ip-exp-value-list/llm.md +175 -0
- package/dist/docs/web-components/ip-icon-button/llm.md +114 -0
- package/dist/docs/web-components/ip-icon-count/llm.md +126 -0
- package/dist/docs/web-components/ip-main-menu/llm.md +219 -0
- package/dist/docs/web-components/ip-main-menu-group/llm.md +114 -0
- package/dist/docs/web-components/ip-main-menu-item/llm.md +104 -0
- package/dist/docs/web-components/ip-main-menu-section/llm.md +95 -0
- package/dist/docs/web-components/ip-main-menu-toggle/llm.md +106 -0
- package/dist/docs/web-components/ip-status-marker/llm.md +87 -0
- package/dist/docs/web-components/ip-tooltip/llm.md +174 -0
- package/dist/docs/web-components/services/i18n/llm.md +151 -0
- package/dist/docs/web-components/services/locale/llm.md +62 -0
- package/dist/llm.md +68 -10
- package/dist/types/components/ip-avatar/ip-avatar.d.ts +105 -0
- package/dist/types/components/ip-avatar-stack/ip-avatar-stack.d.ts +102 -0
- package/dist/types/components/ip-button/ip-button.d.ts +2 -0
- package/dist/types/components/ip-card/ip-card.d.ts +56 -0
- package/dist/types/components/ip-chip/ip-chip.d.ts +67 -0
- package/dist/types/components/ip-chip-group/ip-chip-group.d.ts +80 -0
- package/dist/types/components/ip-date-display/i18n.d.ts +4 -0
- package/dist/types/components/ip-date-display/ip-date-display.d.ts +29 -0
- package/dist/types/components/ip-icon-button/ip-icon-button.d.ts +35 -0
- package/dist/types/components/ip-icon-count/ip-icon-count.d.ts +14 -0
- package/dist/types/components/ip-main-menu/i18n.d.ts +8 -0
- package/dist/types/components/ip-main-menu/ip-main-menu-drawer-styles.d.ts +1 -0
- package/dist/types/components/ip-main-menu/ip-main-menu-state-store.d.ts +24 -0
- package/dist/types/components/ip-main-menu/ip-main-menu.d.ts +81 -0
- package/dist/types/components/ip-main-menu-group/ip-main-menu-group.d.ts +20 -0
- package/dist/types/components/ip-main-menu-item/ip-main-menu-item.d.ts +21 -0
- package/dist/types/components/ip-main-menu-section/ip-main-menu-section.d.ts +7 -0
- package/dist/types/components/ip-main-menu-toggle/i18n.d.ts +4 -0
- package/dist/types/components/ip-main-menu-toggle/ip-main-menu-toggle.d.ts +18 -0
- package/dist/types/components/ip-status-marker/ip-status-marker.d.ts +11 -0
- package/dist/types/components/ip-tooltip/ip-tooltip.d.ts +146 -0
- package/dist/types/components.d.ts +3725 -37
- package/dist/types/experimental/components/ip-exp-data-grid/i18n.d.ts +183 -0
- package/dist/types/experimental/components/ip-exp-data-grid/ip-exp-data-grid-dataset.d.ts +63 -0
- package/dist/types/experimental/components/ip-exp-data-grid/ip-exp-data-grid-date-format.d.ts +20 -0
- package/dist/types/experimental/components/ip-exp-data-grid/ip-exp-data-grid-filter-text.d.ts +25 -0
- package/dist/types/experimental/components/ip-exp-data-grid/ip-exp-data-grid-setup.d.ts +187 -0
- package/dist/types/experimental/components/ip-exp-data-grid/ip-exp-data-grid-template.d.ts +78 -0
- package/dist/types/experimental/components/ip-exp-data-grid/ip-exp-data-grid-value-type.d.ts +29 -0
- package/dist/types/experimental/components/ip-exp-data-grid/ip-exp-data-grid.d.ts +1262 -0
- package/dist/types/experimental/components/ip-exp-data-grid-action/ip-exp-data-grid-action.d.ts +37 -0
- package/dist/types/experimental/components/ip-exp-data-grid-card/ip-exp-data-grid-card.d.ts +38 -0
- package/dist/types/experimental/components/ip-exp-data-grid-column/ip-exp-data-grid-column.d.ts +72 -0
- package/dist/types/experimental/components/ip-exp-data-grid-column-group/ip-exp-data-grid-column-group.d.ts +21 -0
- package/dist/types/experimental/components/ip-exp-date-picker/date-picker-model.d.ts +113 -0
- package/dist/types/experimental/components/ip-exp-date-picker/i18n.d.ts +44 -0
- package/dist/types/experimental/components/ip-exp-date-picker/ip-exp-date-picker.d.ts +307 -0
- package/dist/types/experimental/components/ip-exp-dialog/i18n.d.ts +7 -0
- package/dist/types/experimental/components/ip-exp-dialog/ip-exp-dialog.d.ts +92 -0
- package/dist/types/experimental/components/ip-exp-dropdown-menu/ip-exp-dropdown-menu.d.ts +113 -0
- package/dist/types/experimental/components/ip-exp-dropdown-menu-item/ip-exp-dropdown-menu-item.d.ts +33 -0
- package/dist/types/experimental/components/ip-exp-filter-builder/i18n.d.ts +65 -0
- package/dist/types/experimental/components/ip-exp-filter-builder/ip-exp-filter-builder.d.ts +152 -0
- package/dist/types/experimental/components/ip-exp-split-button/i18n.d.ts +7 -0
- package/dist/types/experimental/components/ip-exp-split-button/ip-exp-split-button.d.ts +69 -0
- package/dist/types/experimental/components/ip-exp-switch/ip-exp-switch.d.ts +74 -0
- package/dist/types/experimental/components/ip-exp-value-list/i18n.d.ts +17 -0
- package/dist/types/experimental/components/ip-exp-value-list/ip-exp-value-list.d.ts +48 -0
- package/dist/types/experimental/grid-engine/aggregate.d.ts +30 -0
- package/dist/types/experimental/grid-engine/bitset.d.ts +50 -0
- package/dist/types/experimental/grid-engine/collation.d.ts +19 -0
- package/dist/types/experimental/grid-engine/column-builder.d.ts +27 -0
- package/dist/types/experimental/grid-engine/column-expression.d.ts +40 -0
- package/dist/types/experimental/grid-engine/column-store.d.ts +71 -0
- package/dist/types/experimental/grid-engine/display-store.d.ts +39 -0
- package/dist/types/experimental/grid-engine/facets.d.ts +27 -0
- package/dist/types/experimental/grid-engine/filter-ast.d.ts +40 -0
- package/dist/types/experimental/grid-engine/filter-builder-model.d.ts +117 -0
- package/dist/types/experimental/grid-engine/filter-eval.d.ts +15 -0
- package/dist/types/experimental/grid-engine/grouping.d.ts +62 -0
- package/dist/types/experimental/grid-engine/highlight.d.ts +29 -0
- package/dist/types/experimental/grid-engine/line-metrics.d.ts +37 -0
- package/dist/types/experimental/grid-engine/naive-search.d.ts +29 -0
- package/dist/types/experimental/grid-engine/query-parser.d.ts +51 -0
- package/dist/types/experimental/grid-engine/search.d.ts +35 -0
- package/dist/types/experimental/grid-engine/sort.d.ts +34 -0
- package/dist/types/experimental/index.d.ts +33 -0
- package/dist/types/experimental/shared/field/field-frame.d.ts +43 -0
- package/dist/types/experimental/shared/field/i18n.d.ts +14 -0
- package/dist/types/home/runner/work/pixel/pixel/.stencil/utils/abbreviate-name.d.ts +2 -0
- package/dist/types/home/runner/work/pixel/pixel/.stencil/utils/get-initials.d.ts +2 -0
- package/dist/types/home/runner/work/pixel/pixel/.stencil/utils/icons.d.ts +102 -0
- package/dist/types/home/runner/work/pixel/pixel/.stencil/utils/media-query.d.ts +2 -0
- package/dist/types/home/runner/work/pixel/pixel/.stencil/utils/xlsx.d.ts +36 -0
- package/dist/types/home/runner/work/pixel/pixel/.stencil/utils/zip.d.ts +18 -0
- package/dist/types/index.d.ts +21 -0
- package/dist/types/services/i18n/i18n.d.ts +134 -0
- package/dist/types/services/index.d.ts +5 -0
- package/dist/types/services/locale/locale.d.ts +23 -0
- package/dist/types/stencil-public-runtime.d.ts +74 -55
- package/dist/web-components/components/experimental.js +19 -0
- package/dist/web-components/components/index.js +1 -1
- package/dist/web-components/components/ip-avatar-stack.d.ts +11 -0
- package/dist/web-components/components/ip-avatar-stack.js +1 -0
- package/dist/web-components/components/ip-avatar.d.ts +11 -0
- package/dist/web-components/components/ip-avatar.js +1 -0
- package/dist/web-components/components/ip-button.js +1 -1
- package/dist/web-components/components/ip-card.d.ts +11 -0
- package/dist/web-components/components/ip-card.js +1 -0
- package/dist/web-components/components/ip-chip-group.d.ts +11 -0
- package/dist/web-components/components/ip-chip-group.js +1 -0
- package/dist/web-components/components/ip-chip.d.ts +11 -0
- package/dist/web-components/components/ip-chip.js +1 -0
- package/dist/web-components/components/ip-date-display.d.ts +11 -0
- package/dist/web-components/components/ip-date-display.js +1 -0
- package/dist/web-components/components/ip-exp-data-grid-action.d.ts +11 -0
- package/dist/web-components/components/ip-exp-data-grid-action.js +1 -0
- package/dist/web-components/components/ip-exp-data-grid-card.d.ts +11 -0
- package/dist/web-components/components/ip-exp-data-grid-card.js +1 -0
- package/dist/web-components/components/ip-exp-data-grid-column-group.d.ts +11 -0
- package/dist/web-components/components/ip-exp-data-grid-column-group.js +1 -0
- package/dist/web-components/components/ip-exp-data-grid-column.d.ts +11 -0
- package/dist/web-components/components/ip-exp-data-grid-column.js +1 -0
- package/dist/web-components/components/ip-exp-data-grid.d.ts +11 -0
- package/dist/web-components/components/ip-exp-data-grid.js +1 -0
- package/dist/web-components/components/ip-exp-date-picker.d.ts +11 -0
- package/dist/web-components/components/ip-exp-date-picker.js +1 -0
- package/dist/web-components/components/ip-exp-dialog.d.ts +11 -0
- package/dist/web-components/components/ip-exp-dialog.js +1 -0
- package/dist/web-components/components/ip-exp-dropdown-menu-item.d.ts +11 -0
- package/dist/web-components/components/ip-exp-dropdown-menu-item.js +1 -0
- package/dist/web-components/components/ip-exp-dropdown-menu.d.ts +11 -0
- package/dist/web-components/components/ip-exp-dropdown-menu.js +1 -0
- package/dist/web-components/components/ip-exp-filter-builder.d.ts +11 -0
- package/dist/web-components/components/ip-exp-filter-builder.js +1 -0
- package/dist/web-components/components/ip-exp-split-button.d.ts +11 -0
- package/dist/web-components/components/ip-exp-split-button.js +1 -0
- package/dist/web-components/components/ip-exp-switch.d.ts +11 -0
- package/dist/web-components/components/ip-exp-switch.js +1 -0
- package/dist/web-components/components/ip-exp-value-list.d.ts +11 -0
- package/dist/web-components/components/ip-exp-value-list.js +1 -0
- package/dist/web-components/components/ip-icon-button.d.ts +11 -0
- package/dist/web-components/components/ip-icon-button.js +1 -0
- package/dist/web-components/components/ip-icon-count.d.ts +11 -0
- package/dist/web-components/components/ip-icon-count.js +1 -0
- package/dist/web-components/components/ip-main-menu-group.d.ts +11 -0
- package/dist/web-components/components/ip-main-menu-group.js +1 -0
- package/dist/web-components/components/ip-main-menu-item.d.ts +11 -0
- package/dist/web-components/components/ip-main-menu-item.js +1 -0
- package/dist/web-components/components/ip-main-menu-section.d.ts +11 -0
- package/dist/web-components/components/ip-main-menu-section.js +1 -0
- package/dist/web-components/components/ip-main-menu-toggle.d.ts +11 -0
- package/dist/web-components/components/ip-main-menu-toggle.js +1 -0
- package/dist/web-components/components/ip-main-menu.d.ts +11 -0
- package/dist/web-components/components/ip-main-menu.js +1 -0
- package/dist/web-components/components/ip-status-marker.d.ts +11 -0
- package/dist/web-components/components/ip-status-marker.js +1 -0
- package/dist/web-components/components/ip-tooltip.d.ts +11 -0
- package/dist/web-components/components/ip-tooltip.js +1 -0
- package/dist/web-components/components/p-02Eg1K7Q.js +1 -0
- package/dist/web-components/components/p-5lZKL5pU.js +1 -0
- package/dist/web-components/components/p-AtiL0xkH.js +1 -0
- package/dist/web-components/components/p-B2RTQjbv.js +1 -0
- package/dist/web-components/components/p-B7Q0nRIB.js +1 -0
- package/dist/web-components/components/p-B8cVaSkf.js +1 -0
- package/dist/web-components/components/p-BAVZt5eT.js +1 -0
- package/dist/web-components/components/p-BTJLJGxK.js +1 -0
- package/dist/web-components/components/p-BaH0ljF8.js +1 -0
- package/dist/web-components/components/p-BoqD_XeW.js +1 -0
- package/dist/web-components/components/p-BwPaf8qV.js +1 -0
- package/dist/web-components/components/p-C-Yd0XyR.js +1 -0
- package/dist/web-components/components/p-CFslB2MQ.js +1 -0
- package/dist/web-components/components/p-CQV0Bd67.js +1 -0
- package/dist/web-components/components/p-CRSkf66C.js +1 -0
- package/dist/web-components/components/p-CTPpnp37.js +1 -0
- package/dist/web-components/components/p-CXYeHWa6.js +1 -0
- package/dist/web-components/components/p-D3ETab0i.js +1 -0
- package/dist/web-components/components/p-D71ISsQB.js +3 -0
- package/dist/web-components/components/p-DF5j2lnn.js +1 -0
- package/dist/web-components/components/p-DYQlk5p6.js +1 -0
- package/dist/web-components/components/p-DbAi7XJ5.js +1 -0
- package/dist/web-components/components/p-Ddl5OmIu.js +1 -0
- package/dist/web-components/components/p-DeFo15B6.js +1 -0
- package/dist/web-components/components/p-DefPpKsB.js +1 -0
- package/dist/web-components/components/p-RuitbCll.js +1 -0
- package/dist/web-components/components/p-VIl8XMWC.js +1 -0
- package/dist/web-components/components/p-W1LNEheS.js +1 -0
- package/dist/web-components/components/p-i-bxsOWr.js +1 -0
- package/dist/web-components/components/p-rLlqXPAQ.js +1 -0
- package/dist/web-components/components/p-vAp9QwI5.js +1 -0
- package/dist/web-components/generated/angular/angular-component-lib/boolean-attribute.d.ts +35 -0
- package/dist/web-components/generated/angular/angular-component-lib/boolean-attribute.js +42 -0
- package/dist/web-components/generated/angular/angular-component-lib/boolean-attribute.ts +43 -0
- package/dist/web-components/generated/angular/boolean-value-accessor.d.ts +9 -0
- package/dist/web-components/generated/angular/boolean-value-accessor.js +37 -0
- package/dist/web-components/generated/angular/components.d.ts +1435 -2
- package/dist/web-components/generated/angular/components.js +2106 -6
- package/dist/web-components/generated/angular/experimental.d.ts +9 -0
- package/dist/web-components/generated/angular/experimental.js +9 -0
- package/dist/web-components/generated/angular/index.d.ts +1 -1
- package/dist/web-components/generated/angular/index.js +29 -1
- package/dist/web-components/generated/angular/stable.d.ts +6 -0
- package/dist/web-components/generated/angular/stable.js +6 -0
- package/dist/web-components/generated/angular/text-value-accessor.d.ts +8 -0
- package/dist/web-components/generated/angular/text-value-accessor.js +34 -0
- package/dist/web-components/generated/angular/value-accessor.d.ts +18 -0
- package/dist/web-components/generated/angular/value-accessor.js +41 -0
- package/dist/web-components/generated/react/components.d.ts +151 -2
- package/dist/web-components/generated/react/components.js +271 -6
- package/dist/web-components/generated/react/experimental.d.ts +8 -0
- package/dist/web-components/generated/react/experimental.js +7 -0
- package/dist/web-components/generated/react/stable.d.ts +7 -0
- package/dist/web-components/generated/react/stable.js +6 -0
- package/dist/web-components/generated/svelte/components.d.ts +56 -0
- package/dist/web-components/generated/vue/components.d.ts +28 -0
- package/dist/web-components/generated/vue/components.js +363 -0
- package/dist/web-components/generated/vue/experimental.d.ts +7 -0
- package/dist/web-components/generated/vue/experimental.js +7 -0
- package/dist/web-components/generated/vue/stable.d.ts +6 -0
- package/dist/web-components/generated/vue/stable.js +6 -0
- package/llms.txt +61 -0
- package/package.json +64 -36
- package/dist/web-components/generated/angular/components.ts +0 -56
- package/dist/web-components/generated/angular/index.ts +0 -6
- package/dist/web-components/generated/react/components.ts +0 -24
- package/dist/web-components/generated/vue/components.ts +0 -21
- /package/dist/{migrations → docs/migrations}/v1-to-v2.md +0 -0
- /package/dist/{esm → docs}/services/theme-service/llm.md +0 -0
|
@@ -0,0 +1,598 @@
|
|
|
1
|
+
# ip-exp-data-grid
|
|
2
|
+
|
|
3
|
+
Virtualised data grid over rows the application supplies.
|
|
4
|
+
|
|
5
|
+
The grid never fetches anything. You hand it rows, it indexes the fields your `ip-exp-data-grid-column`
|
|
6
|
+
children declare, and it answers queries against that index. Row heights and column widths are
|
|
7
|
+
numbers, never measured from content, which is what keeps rows from jumping as data arrives.
|
|
8
|
+
|
|
9
|
+
Nothing is written to disk. The index lives in memory for as long as the page does.
|
|
10
|
+
|
|
11
|
+
> Not finished. Import it from `@norconsult-digital-public/isypixel/experimental/web-components`; the API may change
|
|
12
|
+
> without a major version.
|
|
13
|
+
|
|
14
|
+
## Attributes
|
|
15
|
+
|
|
16
|
+
| Name | Type | Default | Allowed values | Description |
|
|
17
|
+
| --------------------- | --------- | -------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
18
|
+
| `row-height` | `number` | `36` | any positive px | Height of every row. Fixed, so scroll position is arithmetic rather than measurement. |
|
|
19
|
+
| `cell-lines` | `number` | `1` | any positive count | Lines of text a cell may show before the rest is cut off. Rows grow to fit; one line keeps the ellipsis. The settings panel offers 1 to 5. |
|
|
20
|
+
| `plain-text` | `boolean` | `false` | – | Shows only the value in each cell, ignoring the template a column declares. Brings search highlighting back. |
|
|
21
|
+
| `header-height` | `number` | `0` | any positive px | Height of the header row. Zero follows the row height. |
|
|
22
|
+
| `visible-rows` | `number` | `0` | any positive count | Rows to size the viewport for. `0` makes the grid fill its container, which needs a height. |
|
|
23
|
+
| `dataset-id` | `string` | `''` | any id | Shares one index between views. Two elements with the same id read the same index. |
|
|
24
|
+
| `zebra` | `boolean` | `false` | – | Alternating row backgrounds. |
|
|
25
|
+
| `row-lines` | `boolean` | `true` | – | Separator line under each row. |
|
|
26
|
+
| `column-lines` | `boolean` | `true` | – | Separator line between columns. |
|
|
27
|
+
| `row-numbers` | `boolean` | `false` | – | Shows the position of each row in the current order. |
|
|
28
|
+
| `lock-first-column` | `boolean` | `false` | – | Keeps the leftmost column in place while the grid scrolls sideways. |
|
|
29
|
+
| `selection` | `string` | `'none'` | `none`, `single`, `multiple` | Whether rows can be picked, and how many at a time. Adds a column of boxes on the left. |
|
|
30
|
+
| `resizable-columns` | `boolean` | `false` | – | Adds a grip on each column edge for dragging, keyboard resizing and autofit. |
|
|
31
|
+
| `reorderable-columns` | `boolean` | `false` | – | Lets the user drag a heading to move the column, or move it with Ctrl and an arrow key. |
|
|
32
|
+
| `remember-state` | `boolean` | `true` | – | Remembers the setup in sessionStorage, per tab. Needs a `state-key` or a `dataset-id`; without one nothing is stored. |
|
|
33
|
+
| `state-key` | `string` | `''` | any key | Key the setup is stored under. Falls back to `dataset-id`. |
|
|
34
|
+
| `group-by` | `string` | `''` | comma-separated | Fields to group by, outermost first. Only declared columns can be grouped on. |
|
|
35
|
+
| `groups-expanded` | `boolean` | `false` | – | Whether groups start open. Closed by default, so a grouped table opens as an overview. |
|
|
36
|
+
| `group-panel` | `boolean` | `false` | – | Shows a zone above the header where columns can be dropped to group by them. |
|
|
37
|
+
| `aggregate-menu` | `boolean` | `false` | – | Lets the user right-click a heading to choose which figures the column shows. |
|
|
38
|
+
| `view` | `string` | `table` | `table`, `cards`, `auto` | Draws the rows as a table or as cards. Needs an `ip-exp-data-grid-card` child to show cards at all. |
|
|
39
|
+
| `actions-menu` | `boolean` | `false` | – | A column at the right edge whose heading holds the list's commands: columns, settings, Excel export, setup files, reset. |
|
|
40
|
+
| `search` | `string` | `''` | any text or expression | Searched for across every indexed column. Takes the same expressions a filter field does. |
|
|
41
|
+
| `search-box` | `boolean` | `false` | – | Shows the grid's own search box above the header. |
|
|
42
|
+
| `filter-row` | `boolean` | `false` | – | Shows a row of filter fields under the headings, one per column. |
|
|
43
|
+
| `value-list` | `boolean` | `false` | – | Gives each heading a button that opens the column's distinct values to pick from. |
|
|
44
|
+
| `highlight-matches` | `boolean` | `true` | – | Marks the matched text inside the cells. Off leaves the values as they read. |
|
|
45
|
+
|
|
46
|
+
## Properties
|
|
47
|
+
|
|
48
|
+
Set from JavaScript. An array of objects cannot be an attribute.
|
|
49
|
+
|
|
50
|
+
| Name | Type | Default | Description |
|
|
51
|
+
| ------------ | ----------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
52
|
+
| `rows` | `readonly object[]` | `[]` | The rows to show. The application fetches them; the grid indexes them. Any object array, including your own typed interface. |
|
|
53
|
+
| `groupBy` | `string \| readonly string[]` | `''` | Fields to group by. The array form for JavaScript, the comma-separated attribute for markup. |
|
|
54
|
+
| `filterRows` | `readonly BuilderRow[]` | `[]` | Everything filtering the table, as one list. Bind it to share the filter with an `ip-exp-filter-builder` or a card view. |
|
|
55
|
+
| `selected` | `readonly number[]` | `[]` | The picked rows, as indexes into `rows`. Two-way: set it to pick from outside, read it after `ipRowSelectionChange`. |
|
|
56
|
+
|
|
57
|
+
## Slots
|
|
58
|
+
|
|
59
|
+
| Name | Description |
|
|
60
|
+
| ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
61
|
+
| default | `ip-exp-data-grid-column`, `ip-exp-data-grid-column-group`, `ip-exp-data-grid-card` and `ip-exp-data-grid-action` elements. Read as configuration, never rendered. |
|
|
62
|
+
| `empty` | Shown instead of rows when there are none. A message, an illustration, a button to add data. |
|
|
63
|
+
|
|
64
|
+
## Events
|
|
65
|
+
|
|
66
|
+
| Name | Payload | Description |
|
|
67
|
+
| ---------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------- |
|
|
68
|
+
| `ipSortChange` | `{ field: string; direction: 'asc' \| 'desc' } \| null` | The user sorted by a column. `null` when the sort was cleared again. |
|
|
69
|
+
| `ipSetupChange` | `GridSetup` | The setup changed. Store this as "my setup"; see Saved setups below. |
|
|
70
|
+
| `ipSearchChange` | `{ query: string; matches: number }` | The search text changed, with the rows left after it. |
|
|
71
|
+
| `ipFilterChange` | `{ filter: FilterNode \| null; rows: BuilderRow[] }` | The filter changed, whichever surface changed it. |
|
|
72
|
+
| `ipRowSelectionChange` | `{ rows: number[] }` | The picked rows changed, as indexes into `rows`. |
|
|
73
|
+
| `ipSettingsChange` | `GridSettings` | The user changed a display setting in the settings panel. |
|
|
74
|
+
| `ipRowAction` | `{ name: string; row: number; data: object }` | A row action button was pressed. `row` indexes the rows the grid was handed. |
|
|
75
|
+
|
|
76
|
+
## Methods
|
|
77
|
+
|
|
78
|
+
| Name | Description |
|
|
79
|
+
| ----------------------- | --------------------------------------------------------------------------------------- |
|
|
80
|
+
| `getSetup()` | The whole setup as JSON: column order, widths, sort and grouping. |
|
|
81
|
+
| `applySetup(setup)` | Applies a setup, given either as an object or as JSON text. Unknown fields are ignored. |
|
|
82
|
+
| `resetSetup()` | Returns to what the markup declares. |
|
|
83
|
+
| `expandAllGroups(open)` | Opens or closes every group at once. |
|
|
84
|
+
|
|
85
|
+
## Behaviour
|
|
86
|
+
|
|
87
|
+
**Index scope.** Only the fields declared as columns are indexed. Index cost scales with fields
|
|
88
|
+
times rows and field count dominates, so a wide row indexed in full costs several times what the
|
|
89
|
+
displayed columns cost. Nothing outside the declared columns can be sorted.
|
|
90
|
+
|
|
91
|
+
**Indexing is sliced.** A large dataset is indexed in slices of a few milliseconds so the page never
|
|
92
|
+
freezes. While that runs the grid shows a skeleton and reports `aria-busy="true"`. A small dataset
|
|
93
|
+
finishes within the first slice, so no skeleton flashes.
|
|
94
|
+
|
|
95
|
+
**Sorting permutes indices.** Rows are never moved. A numeric column sorts as numbers, so 9 comes
|
|
96
|
+
before 10, and empty cells go last in both directions because an empty cell is the absence of a
|
|
97
|
+
value rather than a small one. Clicking a header cycles ascending, descending, and back to the order
|
|
98
|
+
the rows arrived in. The collation locale comes from `PixelLocaleService`.
|
|
99
|
+
|
|
100
|
+
**Arranging columns.** With `resizable-columns`, each column gets a grip on its trailing edge:
|
|
101
|
+
drag it, or focus it and use the arrow keys, or double-click it to fit the column to the values
|
|
102
|
+
currently on screen. That autofit is the only place a width comes from content, and only because the
|
|
103
|
+
user asked for it. With `reorderable-columns`, a heading can be dragged, or moved with Ctrl and an
|
|
104
|
+
arrow key while the heading is focused. A heading that can be moved shows the grab cursor, and the
|
|
105
|
+
closed-hand cursor while it is being dragged.
|
|
106
|
+
|
|
107
|
+
**Grouping.** `group-by` names the fields to group on, outermost first. Each group becomes one line in
|
|
108
|
+
the same virtualised list as the rows, so a grouped table of a hundred thousand rows costs no more to
|
|
109
|
+
render than a flat one. Opening a group keeps the view where it is, because it is the same list with
|
|
110
|
+
more of it showing; a new sort or a new grouping starts from the top, because it is a different list.
|
|
111
|
+
Only declared columns can be grouped on, since nothing else is indexed.
|
|
112
|
+
|
|
113
|
+
**The grouping zone.** With `group-panel`, a dashed zone appears above the header. Drag a heading
|
|
114
|
+
onto it to group by that column, or hold Ctrl and press G while a groupable heading has focus. Only
|
|
115
|
+
columns declared `groupable` are accepted, and the zone lights up while one is in the air so the
|
|
116
|
+
target is visible before the drop.
|
|
117
|
+
|
|
118
|
+
Each level is an `ip-chip`, and their order is the grouping order, outermost first. Drag one chip onto
|
|
119
|
+
another to change that order, or hold Ctrl and press an arrow key with a chip focused, the same keys
|
|
120
|
+
that move a column in the header. The level number is not printed on the chip, because the order says
|
|
121
|
+
it; it stays in the chip's accessible name, where a user who cannot see the order still needs it.
|
|
122
|
+
The chip's remove button drops that level, and removing the last one ungroups the table.
|
|
123
|
+
|
|
124
|
+
Once grouping has been taken over this way, or by `applySetup`, an empty grouping means no grouping
|
|
125
|
+
rather than a fall back to the `group-by` attribute. Changing that attribute takes grouping back.
|
|
126
|
+
|
|
127
|
+
**Figures.** A column with an `aggregate` shows that figure in the summary row and in every group
|
|
128
|
+
header, aligned under the column it belongs to. The summary row covers the whole result and sits
|
|
129
|
+
sticky at the bottom of the same scroll container as the columns, which is what stops the grid from
|
|
130
|
+
growing a second horizontal scrollbar. Group figures are worked out for the headers actually on
|
|
131
|
+
screen, so a table with thousands of groups does no work nobody sees.
|
|
132
|
+
|
|
133
|
+
The summary row also reports how many rows are left after the search and the filters. With
|
|
134
|
+
`row-numbers` the count sits in the row number column, under the numbers it totals; without it, the
|
|
135
|
+
count leads the first column's cell, labelled the way the other figures are.
|
|
136
|
+
|
|
137
|
+
**Choosing figures.** With `aggregate-menu`, right-clicking a heading opens a menu with sum, average,
|
|
138
|
+
smallest, largest and count. Several can be on at once for one column: they stack under each other,
|
|
139
|
+
in the summary row and in every group header, and both grow to fit them. A grouped list is then two
|
|
140
|
+
line heights rather than one, which the scroll position accounts for. What the user picks replaces what the
|
|
141
|
+
column declared, and turning them all off is a choice the setup remembers. The context menu key opens
|
|
142
|
+
the same menu, since that is what a browser turns into a right-click for whatever has focus.
|
|
143
|
+
|
|
144
|
+
**The command menu.** `actions-menu` gives the grid a column of its own at the right edge, stuck
|
|
145
|
+
there while the table scrolls sideways. Its heading holds a menu of the commands that belong to the
|
|
146
|
+
list rather than to a column: the column picker, the settings, saving the setup to a file, loading
|
|
147
|
+
one back, and a reset that puts the whole arrangement back to what the markup declared.
|
|
148
|
+
|
|
149
|
+
A real column rather than a button floating over the header, because anything focusable inside
|
|
150
|
+
`role="grid"` has to be a real cell in a real row.
|
|
151
|
+
|
|
152
|
+
**Row actions.** The cells under that heading hold one button per `ip-exp-data-grid-action` child, and
|
|
153
|
+
`ipRowAction` reports which was pressed on which row. The column grows to fit them. Without any such
|
|
154
|
+
child the cells stay empty and the column is only as wide as the command menu. See
|
|
155
|
+
`ip-exp-data-grid-action` for the whole of it.
|
|
156
|
+
|
|
157
|
+
**Cell templates.** A column may declare a `<template>` saying what its cells draw, with `[[field]]`
|
|
158
|
+
standing in for a value from the row. It is parsed once and built per visible row as virtual DOM, so
|
|
159
|
+
it costs the twenty rows on screen rather than the five hundred thousand behind them. See
|
|
160
|
+
`ip-exp-data-grid-column` for the whole of it, including why the CSS has to travel inside the template.
|
|
161
|
+
|
|
162
|
+
Only put trusted fields, or fields with a fixed set of values, into a `style` attribute. Never put free
|
|
163
|
+
text from the data there.
|
|
164
|
+
|
|
165
|
+
**Plain text mode.** `plain-text` turns every template off and shows the value instead. The densest
|
|
166
|
+
reading of the table, and the only one where a search marks what it matched: a template decides its
|
|
167
|
+
own content, so the grid cannot reach inside it to wrap a run of text. It leaves the action column,
|
|
168
|
+
the row numbers and the tick boxes alone.
|
|
169
|
+
|
|
170
|
+
**Lines per cell.** `cell-lines` lets a cell show more than one line. The settings panel offers one to five. The rows grow to
|
|
171
|
+
fit the count rather than the text, so a row height is still a number the component works out and
|
|
172
|
+
scroll position is still arithmetic: five hundred thousand rows cost the same to scroll at five lines
|
|
173
|
+
as at one. One line keeps the cheaper ellipsis.
|
|
174
|
+
|
|
175
|
+
There is deliberately no "as many as it takes". That would mean measuring every cell, which is the
|
|
176
|
+
one thing this grid does not do, and is why rows never jump as data arrives.
|
|
177
|
+
|
|
178
|
+
**Export to Excel.** The menu writes what is on screen out as a real `.xlsx`: the visible columns,
|
|
179
|
+
in their current order, and the rows left after the search and the filters, in the sorted order. A
|
|
180
|
+
second command writes only the picked rows, and is off until some are. Values that read as plain
|
|
181
|
+
numbers are written as numbers so Excel can sum them; everything else goes in as text.
|
|
182
|
+
|
|
183
|
+
No spreadsheet library is involved. An `.xlsx` is a ZIP holding five small XML documents, and
|
|
184
|
+
`src/utils/zip.ts` and `src/utils/xlsx.ts` write both. Entries are deflated through
|
|
185
|
+
`CompressionStream` where the platform has it and stored uncompressed where it does not, which are
|
|
186
|
+
both valid ZIP.
|
|
187
|
+
|
|
188
|
+
**A setup as a file.** Save writes `GridSetup` out as JSON named after `state-key` or `dataset-id`,
|
|
189
|
+
for the user to keep or send to a colleague. Load reads one back through `applySetup`, which
|
|
190
|
+
validates it field by field, so a file that is not a setup changes nothing and fields the grid does
|
|
191
|
+
not have are ignored.
|
|
192
|
+
|
|
193
|
+
The grid produces the file itself rather than only the JSON, because the command is in its own menu
|
|
194
|
+
and a menu item that needs the application to implement it before it does anything is a dead item.
|
|
195
|
+
An application that would rather keep setups on a server has `getSetup` and `ipSetupChange`.
|
|
196
|
+
|
|
197
|
+
**The column picker** turns declared columns off and on. A hidden field keeps its place in the order
|
|
198
|
+
and its width, so turning it back on puts it where it was rather than at the end. The last visible
|
|
199
|
+
column cannot be turned off, since nothing would be left to turn it back on from. What is hidden
|
|
200
|
+
travels in `GridSetup.hidden`, so it survives a reload with `remember-state` and moves with a shared
|
|
201
|
+
setup.
|
|
202
|
+
|
|
203
|
+
A column declared with the native `hidden` attribute starts turned off, so a list can offer more
|
|
204
|
+
columns than it shows. Until the user picks something, `GridSetup.hidden` is `null` and the declared
|
|
205
|
+
ones are hidden; Reset list goes back to that. Being the native boolean attribute, `hidden="false"`
|
|
206
|
+
still hides: leave the attribute out, or bind the property (`[hidden]` in Angular).
|
|
207
|
+
|
|
208
|
+
Hiding is separate from a closed column group. A group closing down to one column is a temporary
|
|
209
|
+
narrowing of a band; the picker is the user saying they do not want the column at all.
|
|
210
|
+
|
|
211
|
+
**The settings panel** changes how the table looks, in six groups: row height, lines per cell, style
|
|
212
|
+
and appearance (alternating backgrounds, row and column lines, row numbers, a locked first column),
|
|
213
|
+
filter and search (header filters, grouping, the filter row, the search box, remembering filters),
|
|
214
|
+
whether rows can be picked, and, where a card layout is declared, whether the rows are drawn as a
|
|
215
|
+
table or as cards.
|
|
216
|
+
|
|
217
|
+
Every row says what it does and which way the component ships, so a user can find their way back
|
|
218
|
+
to a default without pressing the button that resets all of them. A button in the heading lays the
|
|
219
|
+
groups out in one column instead of two, for a narrow window.
|
|
220
|
+
|
|
221
|
+
Nothing applies until **Save**. A settings panel is a form, so the table stays still while the
|
|
222
|
+
user is deciding, and closing it leaves things exactly as they were found. **Restore defaults**
|
|
223
|
+
puts the panel back to what the component ships with, still without applying it. Save writes every
|
|
224
|
+
setting onto the element, so a framework binding sees the new values, and `ipSettingsChange` carries
|
|
225
|
+
the lot.
|
|
226
|
+
|
|
227
|
+
These are preferences about how a list should look, not how this list is arranged, so they are
|
|
228
|
+
**not** part of `GridSetup` and the grid does not store them. An application that wants them to
|
|
229
|
+
follow the user has to keep them itself.
|
|
230
|
+
|
|
231
|
+
**Cards.** `view` draws the rows as cards instead of rows: `cards` always, `auto` when the columns
|
|
232
|
+
would not fit the width, `table` never. An `ip-exp-data-grid-card` child says which field goes in which
|
|
233
|
+
part of the card; without one the grid stays a table whatever `view` says.
|
|
234
|
+
|
|
235
|
+
It is the same grid either way. The search, the filters, the sort, the grouping and the picked rows
|
|
236
|
+
all carry across the switch, because only the drawing changes. Group headings look and behave the
|
|
237
|
+
same as in the table, and the picking boxes move onto the cards.
|
|
238
|
+
|
|
239
|
+
You set no card height. The grid measures the first card and holds every other one to it, which is
|
|
240
|
+
safe in a way measuring a table row would not be: every card holds the same roles clipped to the
|
|
241
|
+
same number of lines, so one measurement describes all of them and scrolling stays arithmetic.
|
|
242
|
+
|
|
243
|
+
Cards have no columns, so the command menu moves from the action column into a header above the
|
|
244
|
+
list, in the same corner. A filter button sits beside it, opening the filter dialog.
|
|
245
|
+
|
|
246
|
+
**The filter dialog** holds an `ip-exp-filter-builder` over the declared columns, and the grouping the
|
|
247
|
+
table is arranged by. Columns the index stored as a dictionary have few distinct values and already
|
|
248
|
+
hold them, so those become pickers for nothing; the rest stay text fields. The builder's free-text
|
|
249
|
+
field and the grid's search box are the same search: the dialog opens with what the box holds, and
|
|
250
|
+
applying it writes the field back to `search`.
|
|
251
|
+
|
|
252
|
+
Grouping sits beside the builder rather than inside it, because `ip-exp-filter-builder` is used on its
|
|
253
|
+
own wherever something needs searching, and there is no grouping to speak of there.
|
|
254
|
+
|
|
255
|
+
**Picking rows.** `selection` adds a column of boxes on the left, after the row numbers when those are shown.
|
|
256
|
+
`multiple` gives every row a checkbox and the header a Select all that takes everything left after
|
|
257
|
+
the search and the filters, showing partly filled while only some of them are picked. `single` gives
|
|
258
|
+
every row a radio, and picking one gives the previous one back.
|
|
259
|
+
|
|
260
|
+
Picking is done in that column rather than by clicking anywhere on the row. A click inside a cell
|
|
261
|
+
then still means what the cell says it means, and the keyboard reaches the boxes without the grid
|
|
262
|
+
having to take over the arrow keys.
|
|
263
|
+
|
|
264
|
+
The picked rows are indexes into `rows`, in `selected` and in `ipRowSelectionChange`. Indexes rather
|
|
265
|
+
than keys, because the grid is never told which field identifies a row, and the consumer already
|
|
266
|
+
holds the array they point into. Setting `rows` clears the selection, since the old indexes point at
|
|
267
|
+
an array that is gone. The selection is deliberately **not** part of `GridSetup`: a setup is stored
|
|
268
|
+
and shared, and indexes restored against different data would pick the wrong rows.
|
|
269
|
+
|
|
270
|
+
**One filter, four views of it.** The search box, the filter fields, the value lists and an
|
|
271
|
+
`ip-exp-filter-builder` are not four filters that happen to be ANDed together: they are four ways of
|
|
272
|
+
editing one list of conditions the grid owns. Each shows the same condition rather than a description
|
|
273
|
+
of it, so `{ city, is, Oslo }` reads as `=Oslo` in the filter field, as a ticked Oslo in the value
|
|
274
|
+
list, and as an editable row in the builder. Edit it anywhere and the others follow.
|
|
275
|
+
|
|
276
|
+
`filterRows` is that list, `ipFilterChange` reports every change to it with both the rows and the tree
|
|
277
|
+
they make, and the whole thing travels in the saved setup. Because it is plain data, a card view of the
|
|
278
|
+
same rows can be handed the same filter and pick up where the grid left off.
|
|
279
|
+
|
|
280
|
+
A filter field edits its whole column at once, and a value list edits that column's `is` conditions
|
|
281
|
+
without touching a `>100` the builder put there.
|
|
282
|
+
|
|
283
|
+
**Searching.** `search` narrows the whole list to the rows that carry the text in any indexed column,
|
|
284
|
+
so the application can own the input and bind it, or turn on `search-box` and let the grid own one.
|
|
285
|
+
Both write to the same place. `ipSearchChange` reports the text and how many rows are left.
|
|
286
|
+
|
|
287
|
+
A plain word is answered from the index rather than by reading the rows: a dictionary column is
|
|
288
|
+
searched in its dictionary, so a status column with five distinct values costs five comparisons
|
|
289
|
+
whatever the row count, and text columns are compared as bytes without building a string per cell.
|
|
290
|
+
Typing one more letter narrows the previous answer instead of scanning again.
|
|
291
|
+
|
|
292
|
+
The box also takes the whole expression language below, so `Tromsø & !Bergen` or `>100 | <10` are
|
|
293
|
+
searches too. An expression is evaluated as a tree rather than through the indexed path; a plain word
|
|
294
|
+
still takes the fast one. A half-typed expression is marked and the last answer stands, rather than
|
|
295
|
+
the table emptying on a stray bracket.
|
|
296
|
+
|
|
297
|
+
**Column filters.** `filter-row` puts a field under each heading. Each takes an expression over that
|
|
298
|
+
column, not just a word:
|
|
299
|
+
|
|
300
|
+
| Written | Means |
|
|
301
|
+
| -------------- | --------------------- |
|
|
302
|
+
| `bergen` | contains "bergen" |
|
|
303
|
+
| `=AS` | is exactly "AS" |
|
|
304
|
+
| `!=AS` | is anything else |
|
|
305
|
+
| `^kristian` | starts with |
|
|
306
|
+
| `sund$` | ends with |
|
|
307
|
+
| `>100` | greater than |
|
|
308
|
+
| `10..50` | between, inclusive |
|
|
309
|
+
| `a \| b` | either |
|
|
310
|
+
| `a & !b` | one but not the other |
|
|
311
|
+
| `(a \| b) & c` | grouped |
|
|
312
|
+
|
|
313
|
+
`&`, `|` and `!` can also be written `and`, `or` and `not`, and a space between two terms means `and`.
|
|
314
|
+
|
|
315
|
+
**A column of dates gets a calendar instead.** Where a column holds dates, the filter field under its
|
|
316
|
+
heading is an `ip-exp-date-picker` picking a span, and the span becomes the same `>= & <=` run the field
|
|
317
|
+
would have written by hand, so the advanced filter and the value list see an ordinary condition. The
|
|
318
|
+
column works this out from its own values; `type` on `ip-exp-data-grid-column` overrides it either way.
|
|
319
|
+
|
|
320
|
+
A condition the picker cannot hold sends that cell back to its text field, so a filter built in the
|
|
321
|
+
advanced dialog is always readable where it was made.
|
|
322
|
+
Filters are combined with AND across columns, and the search runs inside what they left, so a narrow
|
|
323
|
+
filter makes the search cheaper as well as narrower.
|
|
324
|
+
|
|
325
|
+
**A field takes a run of conditions, not any expression at all.** `Oslo | Bergen` and `>10 & <100`
|
|
326
|
+
each become conditions; `(a | b) & !c` is refused and the field says why. That is the price of the
|
|
327
|
+
field and the builder always agreeing about what is set, and anything more involved belongs in the
|
|
328
|
+
builder. Mixing `&` and `|` in one field is refused for the same reason: the parser binds them the way
|
|
329
|
+
boolean algebra does and the builder groups them the way its form draws, so a mixed expression would
|
|
330
|
+
mean two different things in the two places it appears.
|
|
331
|
+
|
|
332
|
+
A field whose text does not read is marked and left out rather than applied, so the rows keep their
|
|
333
|
+
last answer while the user is still typing rather than emptying out on a stray bracket. The search
|
|
334
|
+
box, which does not have to agree with a form, still takes the whole language.
|
|
335
|
+
|
|
336
|
+
**Picking values.** `value-list` puts a button in each heading that opens an `ip-exp-value-list` with the
|
|
337
|
+
column's distinct values and a count each. Ticking values narrows the table to any one of them, and
|
|
338
|
+
that combines with the column's filter text rather than replacing it.
|
|
339
|
+
|
|
340
|
+
The counts are taken over what the _other_ columns have already left, not over the whole table, so a
|
|
341
|
+
list offers what is still worth choosing between. A column's own selection is excluded from its own
|
|
342
|
+
count, or ticking one value would leave the list showing only that value. A column with too many
|
|
343
|
+
distinct values to list says so instead.
|
|
344
|
+
|
|
345
|
+
**Marking the matches.** `highlight-matches` is on by default and marks the matched runs inside the
|
|
346
|
+
cells, from the search and the column filters alike. A term under a `!` is not marked, because nothing
|
|
347
|
+
in the cell matched it. The plain text is rendered when nothing is being looked for, so a grid drawing
|
|
348
|
+
thousands of cells a second pays nothing for the feature until it is used.
|
|
349
|
+
|
|
350
|
+
**Column groups.** Wrapping columns in an `ip-exp-data-grid-column-group` draws a shared band above them,
|
|
351
|
+
as a second header row. A `collapsible` band closes down to a single column, the one marked
|
|
352
|
+
`keep-collapsed`, so a quarterly breakdown can fold away to its total. Columns stay inside their group
|
|
353
|
+
when they are reordered, and which groups are closed travels in the saved setup. See the
|
|
354
|
+
`ip-exp-data-grid-column-group` docs.
|
|
355
|
+
|
|
356
|
+
**Saved setups.** `getSetup()` returns one JSON payload holding the column order, the widths, the sort,
|
|
357
|
+
the grouping, the figures per column, the closed column groups, and `filterRows`, which holds the whole filter,
|
|
358
|
+
whichever surface set each part of it. The rows travel as the text the user typed rather than as a
|
|
359
|
+
parsed tree, because the text is what has to reappear in the field. The search text is not in it: a
|
|
360
|
+
search is where you are looking right now, not
|
|
361
|
+
how the table is arranged. There is nothing machine-specific in it, so it can be stored against a user account
|
|
362
|
+
and handed to someone else as it stands. `applySetup()` takes it back, as an object or as text, and is
|
|
363
|
+
deliberately forgiving: fields this grid no longer has are ignored rather than making the whole setup
|
|
364
|
+
fail, so a setup saved before a column was removed still works, and so does one from a colleague whose
|
|
365
|
+
columns differ slightly. `version` says which shape the payload is in.
|
|
366
|
+
|
|
367
|
+
Naming setups, keeping a list of them, letting the user pick one and sharing them is the application's
|
|
368
|
+
job: that belongs to accounts, permissions and storage. The grid's part is the payload.
|
|
369
|
+
|
|
370
|
+
**Storing it in the browser.** `ipSetupChange` carries the whole setup every time it changes, which is
|
|
371
|
+
what an application stores against the signed-in user and hands back through `applySetup()`.
|
|
372
|
+
`remember-state` additionally keeps it in sessionStorage, per tab: useful within a session, and
|
|
373
|
+
deliberately gone when the tab closes, because a setup tied to the machine rather than to an account is
|
|
374
|
+
the wrong thing to leave behind on a shared computer.
|
|
375
|
+
|
|
376
|
+
Nothing else is written to disk. The index itself never leaves memory.
|
|
377
|
+
|
|
378
|
+
**Shared index.** Two elements with the same `dataset-id` read one index, and it survives one of
|
|
379
|
+
them unmounting, which is what a route change in a single-page application looks like. Give the rows
|
|
380
|
+
to one of them; the other reads the same index.
|
|
381
|
+
|
|
382
|
+
## Language
|
|
383
|
+
|
|
384
|
+
The grid's own words go through `PixelI18nService` under the key `ip-exp-data-grid`: the figure labels
|
|
385
|
+
(sum, avg, min, max, count), the grouping hint and level labels, the name of the row number column, the
|
|
386
|
+
value shown for a group whose rows have none, what is announced while the index is built, the search
|
|
387
|
+
and filter placeholders, and the five messages a filter expression can fail with. English and Norwegian
|
|
388
|
+
ship with it; override any of them the way the other components are overridden.
|
|
389
|
+
|
|
390
|
+
The parser itself returns an error code and a character position rather than a message, so what the
|
|
391
|
+
user reads is translated here rather than baked into the engine.
|
|
392
|
+
|
|
393
|
+
Figures are labelled with words rather than symbols, because a sigma tells nobody what it is unless
|
|
394
|
+
they already know.
|
|
395
|
+
|
|
396
|
+
## Accessibility
|
|
397
|
+
|
|
398
|
+
The viewport is a `role="grid"` reporting `aria-rowcount` for the whole dataset rather than the
|
|
399
|
+
rendered slice, so assistive technology hears "row 1002 of 5001" while only a few dozen rows exist
|
|
400
|
+
in the DOM. Every row carries `aria-rowindex` and every cell `aria-colindex`. The sorted column
|
|
401
|
+
carries `aria-sort`. Sort buttons are reachable and operable from the keyboard.
|
|
402
|
+
|
|
403
|
+
With `selection`, the grid reports `aria-multiselectable` when more than one row may be picked, and
|
|
404
|
+
every row carries `aria-selected`. The pick boxes are real checkboxes and radios, so the keyboard
|
|
405
|
+
and assistive technology get them for nothing. The column heading has no room for a word at 44px, so
|
|
406
|
+
it carries its name as visually hidden text rather than as a label on an empty cell.
|
|
407
|
+
|
|
408
|
+
## Design tokens
|
|
409
|
+
|
|
410
|
+
| Token | Role |
|
|
411
|
+
| -------------------------------------------------------- | --------------------------------------------------------------------- |
|
|
412
|
+
| `$ip_color_table_header_background_primary_default` | Header row background |
|
|
413
|
+
| `$ip_color_table_header_background_secondary_default` | Alternating row background |
|
|
414
|
+
| `$ip_color_table_column_header_text_primary_default` | Header text |
|
|
415
|
+
| `$ip_color_table_column_header_border_primary_default` | Line under the header row |
|
|
416
|
+
| `$ip_color_table_column_header_border_secondary_default` | Line between header cells |
|
|
417
|
+
| `$ip_color_table_column_header_icon_primary_default` | Sort direction mark, pick box |
|
|
418
|
+
| `$ip_color_table_row_background_primary_default` | Row background |
|
|
419
|
+
| `$ip_color_table_row_background_primary_hover` | Row background on hover |
|
|
420
|
+
| `$ip_color_table_row_cell_background_primary_default` | Grid background |
|
|
421
|
+
| `$ip_color_table_row_cell_text_primary_default` | Cell text |
|
|
422
|
+
| `$ip_color_table_row_cell_border_primary_default` | Row separator, skeleton bars |
|
|
423
|
+
| `$ip_color_border_primary_default` | Outer border |
|
|
424
|
+
| `$ip_color_button_focus_default` | Focus ring on a sort button |
|
|
425
|
+
| `$ip_color_text_secondary_default` | Row numbers, empty state text |
|
|
426
|
+
| `$ip_color_extended_yellow-300` | Background of a search or filter match in a cell |
|
|
427
|
+
| `$ip_color_extended_yellow-950` | Text of a search or filter match in a cell |
|
|
428
|
+
| `$ip_color_extended_red-600` | An expression in a filter field or the search box that does not parse |
|
|
429
|
+
| `$ip_color_brand_accent_primary_default` | Value list button on a heading whose column is narrowed |
|
|
430
|
+
| `$ip_color_button_background_destructive_default` | A destructive row action |
|
|
431
|
+
| `$ip_color_border_primary_strong` | Border of the option radios in the settings panel |
|
|
432
|
+
| `$ip_color_button_background_secondary_default` | Background of the Close button in the column picker |
|
|
433
|
+
| `$ip_color_button_text_secondary_default` | Text of the Close button in the column picker |
|
|
434
|
+
|
|
435
|
+
## Usage
|
|
436
|
+
|
|
437
|
+
### HTML
|
|
438
|
+
|
|
439
|
+
```html
|
|
440
|
+
<div style="height: 480px">
|
|
441
|
+
<ip-exp-data-grid id="grid" row-numbers zebra lock-first-column>
|
|
442
|
+
<ip-exp-data-grid-column field="name" label="Name" width="220"></ip-exp-data-grid-column>
|
|
443
|
+
<ip-exp-data-grid-column field="city" label="City" width="140"></ip-exp-data-grid-column>
|
|
444
|
+
<ip-exp-data-grid-column field="employees" label="Employees" width="110"></ip-exp-data-grid-column>
|
|
445
|
+
<span slot="empty">No companies yet</span>
|
|
446
|
+
</ip-exp-data-grid>
|
|
447
|
+
</div>
|
|
448
|
+
|
|
449
|
+
<script type="module">
|
|
450
|
+
import '@norconsult-digital-public/isypixel/experimental/web-components';
|
|
451
|
+
|
|
452
|
+
await customElements.whenDefined('ip-exp-data-grid');
|
|
453
|
+
document.getElementById('grid').rows = await fetch('/api/companies').then((response) => response.json());
|
|
454
|
+
</script>
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### React
|
|
458
|
+
|
|
459
|
+
```tsx
|
|
460
|
+
import { IpExpDataGrid, IpExpDataGridColumn } from '@norconsult-digital-public/isypixel/experimental/web-components/react';
|
|
461
|
+
|
|
462
|
+
export function Companies({ rows }: { rows: Company[] }) {
|
|
463
|
+
return (
|
|
464
|
+
<div style={{ height: 480 }}>
|
|
465
|
+
<IpExpDataGrid rows={rows} rowNumbers zebra onIpSortChange={(event) => console.log(event.detail)}>
|
|
466
|
+
<IpExpDataGridColumn field='name' label='Name' width={220} />
|
|
467
|
+
<IpExpDataGridColumn field='city' label='City' width={140} />
|
|
468
|
+
<IpExpDataGridColumn field='employees' label='Employees' width={110} />
|
|
469
|
+
</IpExpDataGrid>
|
|
470
|
+
</div>
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### Vue
|
|
476
|
+
|
|
477
|
+
```vue
|
|
478
|
+
<template>
|
|
479
|
+
<div style="height: 480px">
|
|
480
|
+
<IpExpDataGrid :rows="rows" row-numbers zebra @ipSortChange="onSort">
|
|
481
|
+
<IpExpDataGridColumn field="name" label="Name" :width="220" />
|
|
482
|
+
<IpExpDataGridColumn field="city" label="City" :width="140" />
|
|
483
|
+
<IpExpDataGridColumn field="employees" label="Employees" :width="110" />
|
|
484
|
+
</IpExpDataGrid>
|
|
485
|
+
</div>
|
|
486
|
+
</template>
|
|
487
|
+
|
|
488
|
+
<script setup lang="ts">
|
|
489
|
+
import { IpExpDataGrid, IpExpDataGridColumn } from '@norconsult-digital-public/isypixel/experimental/web-components/vue';
|
|
490
|
+
|
|
491
|
+
const props = defineProps<{ rows: Company[] }>();
|
|
492
|
+
const onSort = (event: CustomEvent) => console.log(event.detail);
|
|
493
|
+
</script>
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
### Angular
|
|
497
|
+
|
|
498
|
+
```ts
|
|
499
|
+
import { IpExpDataGrid, IpExpDataGridColumn } from '@norconsult-digital-public/isypixel/experimental/web-components/angular';
|
|
500
|
+
|
|
501
|
+
@Component({
|
|
502
|
+
selector: 'app-companies',
|
|
503
|
+
imports: [IpExpDataGrid, IpExpDataGridColumn],
|
|
504
|
+
template: `
|
|
505
|
+
<div style="height: 480px">
|
|
506
|
+
<ip-exp-data-grid [rows]="rows()" row-numbers zebra (ipSortChange)="onSort($event)">
|
|
507
|
+
<ip-exp-data-grid-column field="name" label="Name" width="220"></ip-exp-data-grid-column>
|
|
508
|
+
<ip-exp-data-grid-column field="city" label="City" width="140"></ip-exp-data-grid-column>
|
|
509
|
+
<ip-exp-data-grid-column field="employees" label="Employees" width="110"></ip-exp-data-grid-column>
|
|
510
|
+
</ip-exp-data-grid>
|
|
511
|
+
</div>
|
|
512
|
+
`,
|
|
513
|
+
})
|
|
514
|
+
export class CompaniesComponent {
|
|
515
|
+
readonly rows = signal<Company[]>([]);
|
|
516
|
+
|
|
517
|
+
onSort(event: CustomEvent): void {
|
|
518
|
+
console.log(event.detail);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### Svelte
|
|
524
|
+
|
|
525
|
+
```svelte
|
|
526
|
+
<script lang="ts">
|
|
527
|
+
import '@norconsult-digital-public/isypixel/experimental/web-components';
|
|
528
|
+
|
|
529
|
+
let { rows }: { rows: Company[] } = $props();
|
|
530
|
+
</script>
|
|
531
|
+
|
|
532
|
+
<div style="height: 480px">
|
|
533
|
+
<ip-exp-data-grid {rows} row-numbers zebra onipSortChange={(event) => console.log(event.detail)}>
|
|
534
|
+
<ip-exp-data-grid-column field="name" label="Name" width="220"></ip-exp-data-grid-column>
|
|
535
|
+
<ip-exp-data-grid-column field="city" label="City" width="140"></ip-exp-data-grid-column>
|
|
536
|
+
<ip-exp-data-grid-column field="employees" label="Employees" width="110"></ip-exp-data-grid-column>
|
|
537
|
+
</ip-exp-data-grid>
|
|
538
|
+
</div>
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
### Blazor
|
|
542
|
+
|
|
543
|
+
```razor
|
|
544
|
+
<div style="height: 480px">
|
|
545
|
+
<ip-exp-data-grid @ref="grid" row-numbers zebra>
|
|
546
|
+
<ip-exp-data-grid-column field="name" label="Name" width="220"></ip-exp-data-grid-column>
|
|
547
|
+
<ip-exp-data-grid-column field="city" label="City" width="140"></ip-exp-data-grid-column>
|
|
548
|
+
<ip-exp-data-grid-column field="employees" label="Employees" width="110"></ip-exp-data-grid-column>
|
|
549
|
+
</ip-exp-data-grid>
|
|
550
|
+
</div>
|
|
551
|
+
|
|
552
|
+
@code {
|
|
553
|
+
private ElementReference grid;
|
|
554
|
+
|
|
555
|
+
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
556
|
+
{
|
|
557
|
+
if (firstRender)
|
|
558
|
+
{
|
|
559
|
+
// rows is a JS array; set it as a property, not an attribute.
|
|
560
|
+
await JS.InvokeVoidAsync("setGridRows", grid, Companies);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
```js
|
|
567
|
+
// wwwroot/grid-interop.js
|
|
568
|
+
window.setGridRows = (element, rows) => {
|
|
569
|
+
element.rows = rows;
|
|
570
|
+
};
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
### Picking rows
|
|
574
|
+
|
|
575
|
+
One attribute and one event, the same in every framework. The indexes are positions in the `rows`
|
|
576
|
+
array you handed the grid, so the application looks the objects up itself.
|
|
577
|
+
|
|
578
|
+
```html
|
|
579
|
+
<ip-exp-data-grid id="grid" selection="multiple" row-numbers>
|
|
580
|
+
<ip-exp-data-grid-column field="name" label="Name" width="220"></ip-exp-data-grid-column>
|
|
581
|
+
<ip-exp-data-grid-column field="city" label="City" width="140"></ip-exp-data-grid-column>
|
|
582
|
+
</ip-exp-data-grid>
|
|
583
|
+
|
|
584
|
+
<script type="module">
|
|
585
|
+
const grid = document.getElementById('grid');
|
|
586
|
+
grid.rows = companies;
|
|
587
|
+
|
|
588
|
+
grid.addEventListener('ipRowSelectionChange', (event) => {
|
|
589
|
+
const picked = event.detail.rows.map((index) => companies[index]);
|
|
590
|
+
console.log(`${picked.length} companies picked`);
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
// Picking from outside works the same way, so a Clear button is one line.
|
|
594
|
+
document.getElementById('clear').addEventListener('click', () => {
|
|
595
|
+
grid.selected = [];
|
|
596
|
+
});
|
|
597
|
+
</script>
|
|
598
|
+
```
|