@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.
Files changed (241) hide show
  1. package/LICENSE.md +11 -0
  2. package/dist/docs/web-components/ip-avatar/llm.md +176 -0
  3. package/dist/docs/web-components/ip-avatar-stack/llm.md +171 -0
  4. package/dist/{web-components/components → docs/web-components}/ip-button/llm.md +17 -10
  5. package/dist/docs/web-components/ip-card/llm.md +209 -0
  6. package/dist/docs/web-components/ip-chip/llm.md +157 -0
  7. package/dist/docs/web-components/ip-chip-group/llm.md +165 -0
  8. package/dist/docs/web-components/ip-date-display/llm.md +161 -0
  9. package/dist/docs/web-components/ip-exp-data-grid/llm.md +598 -0
  10. package/dist/docs/web-components/ip-exp-data-grid-action/llm.md +193 -0
  11. package/dist/docs/web-components/ip-exp-data-grid-card/llm.md +133 -0
  12. package/dist/docs/web-components/ip-exp-data-grid-column/llm.md +178 -0
  13. package/dist/docs/web-components/ip-exp-data-grid-column-group/llm.md +181 -0
  14. package/dist/docs/web-components/ip-exp-date-picker/llm.md +287 -0
  15. package/dist/docs/web-components/ip-exp-dialog/llm.md +188 -0
  16. package/dist/docs/web-components/ip-exp-dropdown-menu/llm.md +232 -0
  17. package/dist/docs/web-components/ip-exp-dropdown-menu-item/llm.md +177 -0
  18. package/dist/docs/web-components/ip-exp-filter-builder/llm.md +212 -0
  19. package/dist/docs/web-components/ip-exp-split-button/llm.md +211 -0
  20. package/dist/docs/web-components/ip-exp-switch/llm.md +143 -0
  21. package/dist/docs/web-components/ip-exp-value-list/llm.md +175 -0
  22. package/dist/docs/web-components/ip-icon-button/llm.md +114 -0
  23. package/dist/docs/web-components/ip-icon-count/llm.md +126 -0
  24. package/dist/docs/web-components/ip-main-menu/llm.md +219 -0
  25. package/dist/docs/web-components/ip-main-menu-group/llm.md +114 -0
  26. package/dist/docs/web-components/ip-main-menu-item/llm.md +104 -0
  27. package/dist/docs/web-components/ip-main-menu-section/llm.md +95 -0
  28. package/dist/docs/web-components/ip-main-menu-toggle/llm.md +106 -0
  29. package/dist/docs/web-components/ip-status-marker/llm.md +87 -0
  30. package/dist/docs/web-components/ip-tooltip/llm.md +174 -0
  31. package/dist/docs/web-components/services/i18n/llm.md +151 -0
  32. package/dist/docs/web-components/services/locale/llm.md +62 -0
  33. package/dist/llm.md +68 -10
  34. package/dist/types/components/ip-avatar/ip-avatar.d.ts +105 -0
  35. package/dist/types/components/ip-avatar-stack/ip-avatar-stack.d.ts +102 -0
  36. package/dist/types/components/ip-button/ip-button.d.ts +2 -0
  37. package/dist/types/components/ip-card/ip-card.d.ts +56 -0
  38. package/dist/types/components/ip-chip/ip-chip.d.ts +67 -0
  39. package/dist/types/components/ip-chip-group/ip-chip-group.d.ts +80 -0
  40. package/dist/types/components/ip-date-display/i18n.d.ts +4 -0
  41. package/dist/types/components/ip-date-display/ip-date-display.d.ts +29 -0
  42. package/dist/types/components/ip-icon-button/ip-icon-button.d.ts +35 -0
  43. package/dist/types/components/ip-icon-count/ip-icon-count.d.ts +14 -0
  44. package/dist/types/components/ip-main-menu/i18n.d.ts +8 -0
  45. package/dist/types/components/ip-main-menu/ip-main-menu-drawer-styles.d.ts +1 -0
  46. package/dist/types/components/ip-main-menu/ip-main-menu-state-store.d.ts +24 -0
  47. package/dist/types/components/ip-main-menu/ip-main-menu.d.ts +81 -0
  48. package/dist/types/components/ip-main-menu-group/ip-main-menu-group.d.ts +20 -0
  49. package/dist/types/components/ip-main-menu-item/ip-main-menu-item.d.ts +21 -0
  50. package/dist/types/components/ip-main-menu-section/ip-main-menu-section.d.ts +7 -0
  51. package/dist/types/components/ip-main-menu-toggle/i18n.d.ts +4 -0
  52. package/dist/types/components/ip-main-menu-toggle/ip-main-menu-toggle.d.ts +18 -0
  53. package/dist/types/components/ip-status-marker/ip-status-marker.d.ts +11 -0
  54. package/dist/types/components/ip-tooltip/ip-tooltip.d.ts +146 -0
  55. package/dist/types/components.d.ts +3725 -37
  56. package/dist/types/experimental/components/ip-exp-data-grid/i18n.d.ts +183 -0
  57. package/dist/types/experimental/components/ip-exp-data-grid/ip-exp-data-grid-dataset.d.ts +63 -0
  58. package/dist/types/experimental/components/ip-exp-data-grid/ip-exp-data-grid-date-format.d.ts +20 -0
  59. package/dist/types/experimental/components/ip-exp-data-grid/ip-exp-data-grid-filter-text.d.ts +25 -0
  60. package/dist/types/experimental/components/ip-exp-data-grid/ip-exp-data-grid-setup.d.ts +187 -0
  61. package/dist/types/experimental/components/ip-exp-data-grid/ip-exp-data-grid-template.d.ts +78 -0
  62. package/dist/types/experimental/components/ip-exp-data-grid/ip-exp-data-grid-value-type.d.ts +29 -0
  63. package/dist/types/experimental/components/ip-exp-data-grid/ip-exp-data-grid.d.ts +1262 -0
  64. package/dist/types/experimental/components/ip-exp-data-grid-action/ip-exp-data-grid-action.d.ts +37 -0
  65. package/dist/types/experimental/components/ip-exp-data-grid-card/ip-exp-data-grid-card.d.ts +38 -0
  66. package/dist/types/experimental/components/ip-exp-data-grid-column/ip-exp-data-grid-column.d.ts +72 -0
  67. package/dist/types/experimental/components/ip-exp-data-grid-column-group/ip-exp-data-grid-column-group.d.ts +21 -0
  68. package/dist/types/experimental/components/ip-exp-date-picker/date-picker-model.d.ts +113 -0
  69. package/dist/types/experimental/components/ip-exp-date-picker/i18n.d.ts +44 -0
  70. package/dist/types/experimental/components/ip-exp-date-picker/ip-exp-date-picker.d.ts +307 -0
  71. package/dist/types/experimental/components/ip-exp-dialog/i18n.d.ts +7 -0
  72. package/dist/types/experimental/components/ip-exp-dialog/ip-exp-dialog.d.ts +92 -0
  73. package/dist/types/experimental/components/ip-exp-dropdown-menu/ip-exp-dropdown-menu.d.ts +113 -0
  74. package/dist/types/experimental/components/ip-exp-dropdown-menu-item/ip-exp-dropdown-menu-item.d.ts +33 -0
  75. package/dist/types/experimental/components/ip-exp-filter-builder/i18n.d.ts +65 -0
  76. package/dist/types/experimental/components/ip-exp-filter-builder/ip-exp-filter-builder.d.ts +152 -0
  77. package/dist/types/experimental/components/ip-exp-split-button/i18n.d.ts +7 -0
  78. package/dist/types/experimental/components/ip-exp-split-button/ip-exp-split-button.d.ts +69 -0
  79. package/dist/types/experimental/components/ip-exp-switch/ip-exp-switch.d.ts +74 -0
  80. package/dist/types/experimental/components/ip-exp-value-list/i18n.d.ts +17 -0
  81. package/dist/types/experimental/components/ip-exp-value-list/ip-exp-value-list.d.ts +48 -0
  82. package/dist/types/experimental/grid-engine/aggregate.d.ts +30 -0
  83. package/dist/types/experimental/grid-engine/bitset.d.ts +50 -0
  84. package/dist/types/experimental/grid-engine/collation.d.ts +19 -0
  85. package/dist/types/experimental/grid-engine/column-builder.d.ts +27 -0
  86. package/dist/types/experimental/grid-engine/column-expression.d.ts +40 -0
  87. package/dist/types/experimental/grid-engine/column-store.d.ts +71 -0
  88. package/dist/types/experimental/grid-engine/display-store.d.ts +39 -0
  89. package/dist/types/experimental/grid-engine/facets.d.ts +27 -0
  90. package/dist/types/experimental/grid-engine/filter-ast.d.ts +40 -0
  91. package/dist/types/experimental/grid-engine/filter-builder-model.d.ts +117 -0
  92. package/dist/types/experimental/grid-engine/filter-eval.d.ts +15 -0
  93. package/dist/types/experimental/grid-engine/grouping.d.ts +62 -0
  94. package/dist/types/experimental/grid-engine/highlight.d.ts +29 -0
  95. package/dist/types/experimental/grid-engine/line-metrics.d.ts +37 -0
  96. package/dist/types/experimental/grid-engine/naive-search.d.ts +29 -0
  97. package/dist/types/experimental/grid-engine/query-parser.d.ts +51 -0
  98. package/dist/types/experimental/grid-engine/search.d.ts +35 -0
  99. package/dist/types/experimental/grid-engine/sort.d.ts +34 -0
  100. package/dist/types/experimental/index.d.ts +33 -0
  101. package/dist/types/experimental/shared/field/field-frame.d.ts +43 -0
  102. package/dist/types/experimental/shared/field/i18n.d.ts +14 -0
  103. package/dist/types/home/runner/work/pixel/pixel/.stencil/utils/abbreviate-name.d.ts +2 -0
  104. package/dist/types/home/runner/work/pixel/pixel/.stencil/utils/get-initials.d.ts +2 -0
  105. package/dist/types/home/runner/work/pixel/pixel/.stencil/utils/icons.d.ts +102 -0
  106. package/dist/types/home/runner/work/pixel/pixel/.stencil/utils/media-query.d.ts +2 -0
  107. package/dist/types/home/runner/work/pixel/pixel/.stencil/utils/xlsx.d.ts +36 -0
  108. package/dist/types/home/runner/work/pixel/pixel/.stencil/utils/zip.d.ts +18 -0
  109. package/dist/types/index.d.ts +21 -0
  110. package/dist/types/services/i18n/i18n.d.ts +134 -0
  111. package/dist/types/services/index.d.ts +5 -0
  112. package/dist/types/services/locale/locale.d.ts +23 -0
  113. package/dist/types/stencil-public-runtime.d.ts +74 -55
  114. package/dist/web-components/components/experimental.js +19 -0
  115. package/dist/web-components/components/index.js +1 -1
  116. package/dist/web-components/components/ip-avatar-stack.d.ts +11 -0
  117. package/dist/web-components/components/ip-avatar-stack.js +1 -0
  118. package/dist/web-components/components/ip-avatar.d.ts +11 -0
  119. package/dist/web-components/components/ip-avatar.js +1 -0
  120. package/dist/web-components/components/ip-button.js +1 -1
  121. package/dist/web-components/components/ip-card.d.ts +11 -0
  122. package/dist/web-components/components/ip-card.js +1 -0
  123. package/dist/web-components/components/ip-chip-group.d.ts +11 -0
  124. package/dist/web-components/components/ip-chip-group.js +1 -0
  125. package/dist/web-components/components/ip-chip.d.ts +11 -0
  126. package/dist/web-components/components/ip-chip.js +1 -0
  127. package/dist/web-components/components/ip-date-display.d.ts +11 -0
  128. package/dist/web-components/components/ip-date-display.js +1 -0
  129. package/dist/web-components/components/ip-exp-data-grid-action.d.ts +11 -0
  130. package/dist/web-components/components/ip-exp-data-grid-action.js +1 -0
  131. package/dist/web-components/components/ip-exp-data-grid-card.d.ts +11 -0
  132. package/dist/web-components/components/ip-exp-data-grid-card.js +1 -0
  133. package/dist/web-components/components/ip-exp-data-grid-column-group.d.ts +11 -0
  134. package/dist/web-components/components/ip-exp-data-grid-column-group.js +1 -0
  135. package/dist/web-components/components/ip-exp-data-grid-column.d.ts +11 -0
  136. package/dist/web-components/components/ip-exp-data-grid-column.js +1 -0
  137. package/dist/web-components/components/ip-exp-data-grid.d.ts +11 -0
  138. package/dist/web-components/components/ip-exp-data-grid.js +1 -0
  139. package/dist/web-components/components/ip-exp-date-picker.d.ts +11 -0
  140. package/dist/web-components/components/ip-exp-date-picker.js +1 -0
  141. package/dist/web-components/components/ip-exp-dialog.d.ts +11 -0
  142. package/dist/web-components/components/ip-exp-dialog.js +1 -0
  143. package/dist/web-components/components/ip-exp-dropdown-menu-item.d.ts +11 -0
  144. package/dist/web-components/components/ip-exp-dropdown-menu-item.js +1 -0
  145. package/dist/web-components/components/ip-exp-dropdown-menu.d.ts +11 -0
  146. package/dist/web-components/components/ip-exp-dropdown-menu.js +1 -0
  147. package/dist/web-components/components/ip-exp-filter-builder.d.ts +11 -0
  148. package/dist/web-components/components/ip-exp-filter-builder.js +1 -0
  149. package/dist/web-components/components/ip-exp-split-button.d.ts +11 -0
  150. package/dist/web-components/components/ip-exp-split-button.js +1 -0
  151. package/dist/web-components/components/ip-exp-switch.d.ts +11 -0
  152. package/dist/web-components/components/ip-exp-switch.js +1 -0
  153. package/dist/web-components/components/ip-exp-value-list.d.ts +11 -0
  154. package/dist/web-components/components/ip-exp-value-list.js +1 -0
  155. package/dist/web-components/components/ip-icon-button.d.ts +11 -0
  156. package/dist/web-components/components/ip-icon-button.js +1 -0
  157. package/dist/web-components/components/ip-icon-count.d.ts +11 -0
  158. package/dist/web-components/components/ip-icon-count.js +1 -0
  159. package/dist/web-components/components/ip-main-menu-group.d.ts +11 -0
  160. package/dist/web-components/components/ip-main-menu-group.js +1 -0
  161. package/dist/web-components/components/ip-main-menu-item.d.ts +11 -0
  162. package/dist/web-components/components/ip-main-menu-item.js +1 -0
  163. package/dist/web-components/components/ip-main-menu-section.d.ts +11 -0
  164. package/dist/web-components/components/ip-main-menu-section.js +1 -0
  165. package/dist/web-components/components/ip-main-menu-toggle.d.ts +11 -0
  166. package/dist/web-components/components/ip-main-menu-toggle.js +1 -0
  167. package/dist/web-components/components/ip-main-menu.d.ts +11 -0
  168. package/dist/web-components/components/ip-main-menu.js +1 -0
  169. package/dist/web-components/components/ip-status-marker.d.ts +11 -0
  170. package/dist/web-components/components/ip-status-marker.js +1 -0
  171. package/dist/web-components/components/ip-tooltip.d.ts +11 -0
  172. package/dist/web-components/components/ip-tooltip.js +1 -0
  173. package/dist/web-components/components/p-02Eg1K7Q.js +1 -0
  174. package/dist/web-components/components/p-5lZKL5pU.js +1 -0
  175. package/dist/web-components/components/p-AtiL0xkH.js +1 -0
  176. package/dist/web-components/components/p-B2RTQjbv.js +1 -0
  177. package/dist/web-components/components/p-B7Q0nRIB.js +1 -0
  178. package/dist/web-components/components/p-B8cVaSkf.js +1 -0
  179. package/dist/web-components/components/p-BAVZt5eT.js +1 -0
  180. package/dist/web-components/components/p-BTJLJGxK.js +1 -0
  181. package/dist/web-components/components/p-BaH0ljF8.js +1 -0
  182. package/dist/web-components/components/p-BoqD_XeW.js +1 -0
  183. package/dist/web-components/components/p-BwPaf8qV.js +1 -0
  184. package/dist/web-components/components/p-C-Yd0XyR.js +1 -0
  185. package/dist/web-components/components/p-CFslB2MQ.js +1 -0
  186. package/dist/web-components/components/p-CQV0Bd67.js +1 -0
  187. package/dist/web-components/components/p-CRSkf66C.js +1 -0
  188. package/dist/web-components/components/p-CTPpnp37.js +1 -0
  189. package/dist/web-components/components/p-CXYeHWa6.js +1 -0
  190. package/dist/web-components/components/p-D3ETab0i.js +1 -0
  191. package/dist/web-components/components/p-D71ISsQB.js +3 -0
  192. package/dist/web-components/components/p-DF5j2lnn.js +1 -0
  193. package/dist/web-components/components/p-DYQlk5p6.js +1 -0
  194. package/dist/web-components/components/p-DbAi7XJ5.js +1 -0
  195. package/dist/web-components/components/p-Ddl5OmIu.js +1 -0
  196. package/dist/web-components/components/p-DeFo15B6.js +1 -0
  197. package/dist/web-components/components/p-DefPpKsB.js +1 -0
  198. package/dist/web-components/components/p-RuitbCll.js +1 -0
  199. package/dist/web-components/components/p-VIl8XMWC.js +1 -0
  200. package/dist/web-components/components/p-W1LNEheS.js +1 -0
  201. package/dist/web-components/components/p-i-bxsOWr.js +1 -0
  202. package/dist/web-components/components/p-rLlqXPAQ.js +1 -0
  203. package/dist/web-components/components/p-vAp9QwI5.js +1 -0
  204. package/dist/web-components/generated/angular/angular-component-lib/boolean-attribute.d.ts +35 -0
  205. package/dist/web-components/generated/angular/angular-component-lib/boolean-attribute.js +42 -0
  206. package/dist/web-components/generated/angular/angular-component-lib/boolean-attribute.ts +43 -0
  207. package/dist/web-components/generated/angular/boolean-value-accessor.d.ts +9 -0
  208. package/dist/web-components/generated/angular/boolean-value-accessor.js +37 -0
  209. package/dist/web-components/generated/angular/components.d.ts +1435 -2
  210. package/dist/web-components/generated/angular/components.js +2106 -6
  211. package/dist/web-components/generated/angular/experimental.d.ts +9 -0
  212. package/dist/web-components/generated/angular/experimental.js +9 -0
  213. package/dist/web-components/generated/angular/index.d.ts +1 -1
  214. package/dist/web-components/generated/angular/index.js +29 -1
  215. package/dist/web-components/generated/angular/stable.d.ts +6 -0
  216. package/dist/web-components/generated/angular/stable.js +6 -0
  217. package/dist/web-components/generated/angular/text-value-accessor.d.ts +8 -0
  218. package/dist/web-components/generated/angular/text-value-accessor.js +34 -0
  219. package/dist/web-components/generated/angular/value-accessor.d.ts +18 -0
  220. package/dist/web-components/generated/angular/value-accessor.js +41 -0
  221. package/dist/web-components/generated/react/components.d.ts +151 -2
  222. package/dist/web-components/generated/react/components.js +271 -6
  223. package/dist/web-components/generated/react/experimental.d.ts +8 -0
  224. package/dist/web-components/generated/react/experimental.js +7 -0
  225. package/dist/web-components/generated/react/stable.d.ts +7 -0
  226. package/dist/web-components/generated/react/stable.js +6 -0
  227. package/dist/web-components/generated/svelte/components.d.ts +56 -0
  228. package/dist/web-components/generated/vue/components.d.ts +28 -0
  229. package/dist/web-components/generated/vue/components.js +363 -0
  230. package/dist/web-components/generated/vue/experimental.d.ts +7 -0
  231. package/dist/web-components/generated/vue/experimental.js +7 -0
  232. package/dist/web-components/generated/vue/stable.d.ts +6 -0
  233. package/dist/web-components/generated/vue/stable.js +6 -0
  234. package/llms.txt +61 -0
  235. package/package.json +64 -36
  236. package/dist/web-components/generated/angular/components.ts +0 -56
  237. package/dist/web-components/generated/angular/index.ts +0 -6
  238. package/dist/web-components/generated/react/components.ts +0 -24
  239. package/dist/web-components/generated/vue/components.ts +0 -21
  240. /package/dist/{migrations → docs/migrations}/v1-to-v2.md +0 -0
  241. /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
+ ```