@sebgroup/green-core 2.35.1 → 2.37.0

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 (39) hide show
  1. package/components/button/button.trans.styles.scss.js +1 -1
  2. package/components/calendar/calendar.trans.styles.scss.js +1 -1
  3. package/components/context-menu/context-menu.trans.styles.scss.js +1 -1
  4. package/components/datepicker/datepicker.trans.styles.scss.js +1 -1
  5. package/components/dialog/dialog.component.d.ts +22 -2
  6. package/components/dialog/dialog.component.js +104 -23
  7. package/components/formatted-text/date/date-time-formatter.js +1 -3
  8. package/components/grouped-list/grouped-list.trans.styles.scss.js +1 -1
  9. package/components/pagination/pagination.component.js +11 -8
  10. package/components/popover/popover.trans.styles.scss.js +1 -1
  11. package/components/segmented-control/segment/segment.trans.styles.scss.js +1 -1
  12. package/components/segmented-control/segmented-control.trans.styles.css.js +1 -1
  13. package/components/table/table.component.d.ts +30 -1
  14. package/components/table/table.component.js +205 -203
  15. package/components/table/table.stories.data.d.ts +33 -47
  16. package/components/table/table.stories.data.js +308 -287
  17. package/components/table/table.styles.js +196 -11
  18. package/components/table/table.types.d.ts +24 -81
  19. package/components/table/table.types.js +40 -10
  20. package/components/theme/chlorophyll-tokens.scss.js +1 -1
  21. package/custom-elements.json +21506 -21247
  22. package/gds-element.js +1 -1
  23. package/generated/mcp/components.json +1 -1
  24. package/generated/mcp/dialog/api.md +8 -4
  25. package/generated/mcp/icons.json +1 -1
  26. package/generated/mcp/index.json +1 -1
  27. package/generated/mcp/table/api.md +4 -1
  28. package/generated/react/dialog/index.d.ts +2 -1
  29. package/generated/react/index.d.ts +1 -1
  30. package/generated/react/index.js +1 -1
  31. package/generated/react/table/index.d.ts +3 -1
  32. package/package.json +1 -1
  33. package/primitives/field-base/field-base.trans.styles.scss.js +1 -1
  34. package/primitives/listbox/listbox.trans.styles.scss.js +1 -1
  35. package/primitives/listbox/option.trans.styles.scss.js +1 -1
  36. package/primitives/menu/menu-heading.trans.styles.scss.js +1 -1
  37. package/utils/helpers/custom-element-scoping.js +1 -1
  38. package/utils/helpers/id.d.ts +0 -3
  39. package/utils/helpers/id.js +6 -1
@@ -5,7 +5,7 @@ import {
5
5
  __privateMethod,
6
6
  __privateSet
7
7
  } from "../../chunks/chunk.QU3DSPNU.js";
8
- var _cache, _cacheDuration, _templateCache, _GdsTable_instances, Density_get, hasSelection_get, isAllSelected_get, isPartialSelection_get, getCacheKey_fn, isCacheValid_fn, loadData_fn, getSlotContent_fn, renderCell_fn, renderCellContent_fn, renderSortIcon_fn, hasHeaderContent_fn, renderHeaderControls_fn, renderColumnHeader_fn, renderActionsHeader_fn, renderSelectableHeader_fn, renderColumnHeaders_fn, renderTableHeader_fn, renderTableCell_fn, renderSelectableCell_fn, renderRowCells_fn, renderActionsCell_fn, renderTableRow_fn, renderCheckbox_fn, renderSkeletonCell_fn, renderSkeletonRow_fn, renderTableBody_fn, renderTable_fn, renderErrorState_fn, renderEmptyState_fn, renderFooter_fn, renderHeadline_fn, handleSearch_fn, handleSearchClear_fn, handleSort_fn, handlePageChange_fn, handlePageSizeChange_fn, handleColumnVisibility_fn, handleSelectAll_fn, handleRowSelect_fn, selectAllInternal_fn, clearSelectionInternal_fn, emitSelectionChange_fn, initializeScrollTracking_fn, updateVerticalScrollState_fn, updateHorizontalScrollState_fn;
8
+ var _cache, _cacheDuration, _GdsTable_instances, Density_get, hasSelection_get, isAllSelected_get, isPartialSelection_get, getCacheKey_fn, isCacheValid_fn, loadData_fn, getRowKey_fn, renderCellWrapped_fn, renderMobileLabel_fn, renderSlotElement_fn, renderCellContent_fn, renderSortIcon_fn, hasHeaderContent_fn, renderHeaderControls_fn, renderColumnHeader_fn, renderActionsHeader_fn, renderSelectableHeader_fn, renderColumnHeaders_fn, renderTableHeader_fn, renderTableCell_fn, renderSelectableCell_fn, renderRowCells_fn, renderActionsCell_fn, renderTableRow_fn, renderCheckbox_fn, renderSkeletonCell_fn, renderSkeletonRow_fn, renderTableBody_fn, renderTableFoot_fn, renderTable_fn, renderErrorState_fn, renderEmptyState_fn, renderFooter_fn, renderHeadline_fn, handleSearch_fn, handleSearchClear_fn, handleSort_fn, handlePageChange_fn, handlePageSizeChange_fn, handleColumnVisibility_fn, handleSelectAll_fn, handleRowSelect_fn, selectAllInternal_fn, clearSelectionInternal_fn, emitSelectionChange_fn, initializeScrollTracking_fn, updateVerticalScrollState_fn, updateHorizontalScrollState_fn;
9
9
  import { localized, msg } from "@lit/localize";
10
10
  import { property, state } from "lit/decorators.js";
11
11
  import { classMap } from "lit/directives/class-map.js";
@@ -29,7 +29,6 @@ let GdsTable = class extends GdsElement {
29
29
  __privateAdd(this, _GdsTable_instances);
30
30
  __privateAdd(this, _cache, {});
31
31
  __privateAdd(this, _cacheDuration, 5 * 60 * 1e3);
32
- __privateAdd(this, _templateCache, /* @__PURE__ */ new Map());
33
32
  this.headlineTag = "h2";
34
33
  this.options = [5, 10, 20, 50, 100];
35
34
  this.page = 1;
@@ -37,6 +36,7 @@ let GdsTable = class extends GdsElement {
37
36
  this.columns = [];
38
37
  this.density = "comfortable";
39
38
  this.selectable = false;
39
+ this.disableSelectAll = false;
40
40
  this.responsive = false;
41
41
  this.plain = false;
42
42
  this.searchable = false;
@@ -65,6 +65,14 @@ let GdsTable = class extends GdsElement {
65
65
  __privateSet(this, _cache, {});
66
66
  __privateMethod(this, _GdsTable_instances, loadData_fn).call(this);
67
67
  }
68
+ _onPageChange() {
69
+ this._view = { ...this._view, page: Number(this.page ?? 1) };
70
+ __privateMethod(this, _GdsTable_instances, loadData_fn).call(this);
71
+ }
72
+ _onRowsChange() {
73
+ this._view = { ...this._view, rows: Number(this.rows ?? 10), page: 1 };
74
+ __privateMethod(this, _GdsTable_instances, loadData_fn).call(this);
75
+ }
68
76
  _onColumnsChange() {
69
77
  __privateSet(this, _cache, {});
70
78
  this._view = {
@@ -147,7 +155,6 @@ let GdsTable = class extends GdsElement {
147
155
  };
148
156
  _cache = new WeakMap();
149
157
  _cacheDuration = new WeakMap();
150
- _templateCache = new WeakMap();
151
158
  _GdsTable_instances = new WeakSet();
152
159
  Density_get = function() {
153
160
  return Types.DENSITY_CONFIG[this.density];
@@ -182,6 +189,18 @@ loadData_fn = async function() {
182
189
  this._rowsState = cachedData.rows;
183
190
  this._total = cachedData.total;
184
191
  this._loaded = false;
192
+ this.dispatchCustomEvent("gds-table-data-loaded", {
193
+ detail: {
194
+ rows: cachedData.rows,
195
+ total: cachedData.total,
196
+ page: this._view.page,
197
+ rowsPerPage: this._view.rows,
198
+ searchQuery: this._view.searchQuery,
199
+ sortColumn: this._view.sortColumn,
200
+ sortDirection: this._view.sortDirection
201
+ },
202
+ bubbles: true
203
+ });
185
204
  return;
186
205
  }
187
206
  }
@@ -208,7 +227,14 @@ loadData_fn = async function() {
208
227
  this._selected.clear();
209
228
  this._loaded = false;
210
229
  this.dispatchCustomEvent("gds-table-data-loaded", {
211
- detail: response,
230
+ detail: {
231
+ ...response,
232
+ page: this._view.page,
233
+ rowsPerPage: this._view.rows,
234
+ searchQuery: this._view.searchQuery,
235
+ sortColumn: this._view.sortColumn,
236
+ sortDirection: this._view.sortDirection
237
+ },
212
238
  bubbles: true
213
239
  });
214
240
  } catch (error) {
@@ -222,190 +248,64 @@ loadData_fn = async function() {
222
248
  }
223
249
  };
224
250
  /**
225
- * Retrieves template content for the given slot name.
226
- * Uses caching to prevent repeated DOM queries for better performance in large tables.
251
+ * Gets the unique key for slot naming (prioritizes: custom key > row.id > index)
227
252
  */
228
- getSlotContent_fn = function(slot) {
229
- if (!slot) return null;
230
- if (!__privateGet(this, _templateCache).has(slot)) {
231
- const template = this.querySelector(
232
- `template[name="${slot}"]`
233
- );
234
- __privateGet(this, _templateCache).set(slot, template);
253
+ getRowKey_fn = function(row, index, slotKey) {
254
+ if (typeof slotKey === "string" || typeof slotKey === "number") {
255
+ return slotKey;
235
256
  }
236
- return __privateGet(this, _templateCache).get(slot)?.content.cloneNode(true);
237
- };
238
- renderCell_fn = function(config, row) {
239
- if (!config) return null;
240
- if (Array.isArray(config)) {
241
- return config.map((c) => __privateMethod(this, _GdsTable_instances, renderCell_fn).call(this, c, row));
242
- }
243
- const resolve = (value) => typeof value === "function" ? value(row) : value;
244
- switch (config.type) {
245
- case "badge": {
246
- const variant = resolve(config.variant) || "information";
247
- const size = resolve(config.size) || __privateGet(this, _GdsTable_instances, Density_get).badge;
248
- return html`
249
- <gds-badge size="${size}" variant="${variant}">
250
- ${resolve(config.value)}
251
- </gds-badge>
252
- `;
253
- }
254
- case "image": {
255
- const src = resolve(config.src);
256
- if (!src) return null;
257
- const width = resolve(config.width) || "24px";
258
- const height = resolve(config.height) || "24px";
259
- const borderRadius = resolve(config["border-radius"]) || "max";
260
- const objectFit = resolve(config["object-fit"]) || "cover";
261
- const alt = resolve(config.alt) || "";
262
- return html`
263
- <gds-img
264
- src="${src}"
265
- alt="${alt}"
266
- width="${width}"
267
- height="${height}"
268
- border-radius="${borderRadius}"
269
- object-fit="${objectFit}"
270
- object-position="center"
271
- ></gds-img>
272
- `;
273
- }
274
- case "icon": {
275
- const template = resolve(config.template);
276
- const size = resolve(config.size);
277
- const color = resolve(config.color);
278
- const clonedSlot = __privateMethod(this, _GdsTable_instances, getSlotContent_fn).call(this, template);
279
- if (!clonedSlot) return null;
280
- if (clonedSlot instanceof DocumentFragment) {
281
- const iconElement = clonedSlot.firstElementChild;
282
- if (iconElement) {
283
- if (size) iconElement.setAttribute("size", size);
284
- if (color) iconElement.setAttribute("color", color);
285
- }
286
- }
287
- return clonedSlot;
288
- }
289
- case "button": {
290
- const size = resolve(config.size) || __privateGet(this, _GdsTable_instances, Density_get).button;
291
- const variant = resolve(config.variant);
292
- const rank = resolve(config.rank);
293
- const label = resolve(config.label);
294
- const template = resolve(config.template);
295
- const clonedSlot = __privateMethod(this, _GdsTable_instances, getSlotContent_fn).call(this, template);
296
- const content = [label, clonedSlot];
297
- return html`
298
- <gds-button
299
- size="${size}"
300
- variant="${variant || "neutral"}"
301
- rank="${rank || "secondary"}"
302
- @click="${(e) => {
303
- e.stopPropagation();
304
- config.onClick(row);
305
- }}"
306
- >
307
- ${content}
308
- </gds-button>
309
- `;
310
- }
311
- case "link": {
312
- const href = resolve(config.href);
313
- if (!href) return null;
314
- const label = resolve(config.label);
315
- const target = resolve(config.target);
316
- const download = resolve(config.download);
317
- const template = resolve(config.template);
318
- const clonedSlot = __privateMethod(this, _GdsTable_instances, getSlotContent_fn).call(this, template);
319
- const content = [label, clonedSlot];
320
- return html`
321
- <gds-link
322
- href=${ifDefined(href)}
323
- target=${ifDefined(target)}
324
- .download=${download}
325
- text-decoration="underline"
326
- >
327
- ${content}
328
- </gds-link>
329
- `;
330
- }
331
- case "context-menu": {
332
- const items = config.items;
333
- const size = __privateGet(this, _GdsTable_instances, Density_get).button;
334
- return html`
335
- <gds-context-menu>
336
- <gds-button
337
- slot="trigger"
338
- size="${size}"
339
- rank="tertiary"
340
- label="${msg("Actions")}"
341
- >
342
- <gds-icon-dot-grid-one-horizontal></gds-icon-dot-grid-one-horizontal>
343
- </gds-button>
344
- ${items.map((item) => {
345
- const label = resolve(item.label);
346
- return html`
347
- <gds-menu-item @click="${() => item.onClick(row)}">
348
- ${label}
349
- </gds-menu-item>
350
- `;
351
- })}
352
- </gds-context-menu>
353
- `;
354
- }
355
- case "formatted-number": {
356
- const value = resolve(config.value);
357
- const formatter = Table.FormatNumber[config.format || "decimalsAndThousands"];
358
- return formatter(value, config.locale, config.currency, config.decimals);
359
- }
360
- case "formatted-account": {
361
- const value = resolve(config.value);
362
- const formatter = Table.FormatAccount[config.format || "seb-account"];
363
- return formatter(value);
364
- }
365
- case "formatted-date": {
366
- const value = resolve(config.value);
367
- const formatter = Table.FormatDate[config.format || "dateLong"];
368
- return formatter(value, config.locale);
369
- }
370
- default:
371
- return null;
257
+ const rowId = row?.id;
258
+ if (typeof rowId === "string" || typeof rowId === "number") {
259
+ return rowId;
372
260
  }
261
+ return index + 1;
262
+ };
263
+ renderCellWrapped_fn = function(content) {
264
+ return html`<span class="cell-wrapped-content">${content}</span>`;
265
+ };
266
+ renderMobileLabel_fn = function(column) {
267
+ return html`<span class="column-label" aria-hidden="true">
268
+ ${column.label}:
269
+ </span>`;
270
+ };
271
+ renderSlotElement_fn = function(columnKey, rowKey, slotId) {
272
+ const slotName = `${columnKey}:${rowKey}:${slotId}`;
273
+ return html`<slot name="${slotName}"></slot>`;
373
274
  };
374
275
  /**
375
- * Renders the content of a table cell with support for custom transformations,
376
- * cell types, and responsive mobile labels.
276
+ * Renders cell content with proper ordering and wrapping.
377
277
  *
378
- * Value resolution priority:
379
- * 1. column.value - Direct transform function
380
- * 2. cell.value - Cell type configuration (badge, button, etc.)
381
- * 3. row[column.key] - Raw data value
278
+ * **Slot-based content:**
279
+ * - Renders in exact order: ['lead', 'value', 'button'] icon, text, button
280
+ * - Wraps value when column.justify is set (for flexbox)
281
+ * - Slots stay unwrapped
282
+ *
283
+ * **Plain content:**
284
+ * - Wraps when column.justify is set, otherwise renders directly
382
285
  */
383
- renderCellContent_fn = function(row, column) {
384
- const { cell } = column;
385
- let value;
386
- if (column.value) {
387
- value = column.value(row);
388
- } else if (cell?.value) {
389
- value = __privateMethod(this, _GdsTable_instances, renderCell_fn).call(this, cell.value, row);
286
+ renderCellContent_fn = function(row, column, index) {
287
+ const rawValue = column.value ? column.value(row) : row[column.key];
288
+ const isMobile = this._isMobile && this.responsive;
289
+ const shouldWrap = !!column.justify;
290
+ let content;
291
+ if (Types.isSlotValue(rawValue)) {
292
+ const rowKey = __privateMethod(this, _GdsTable_instances, getRowKey_fn).call(this, row, index, rawValue.key);
293
+ content = rawValue.slots.map((slotItem) => {
294
+ if (slotItem === "value") {
295
+ if (rawValue.value === void 0) return null;
296
+ return shouldWrap ? __privateMethod(this, _GdsTable_instances, renderCellWrapped_fn).call(this, rawValue.value) : rawValue.value;
297
+ }
298
+ return __privateMethod(this, _GdsTable_instances, renderSlotElement_fn).call(this, column.key, rowKey, slotItem);
299
+ });
390
300
  } else {
391
- value = row[column.key];
301
+ content = shouldWrap ? __privateMethod(this, _GdsTable_instances, renderCellWrapped_fn).call(this, rawValue) : rawValue;
392
302
  }
393
- const processedValue = column.justify ? html`<span>${value}</span>` : value;
394
- const isResponsive = this._isMobile && this.responsive;
395
- const mobileLabel = isResponsive ? html`
396
- <span class="column-label" aria-hidden="true">
397
- ${column.label}:
398
- </span>
399
- ` : null;
400
- const ariaLabel = isResponsive ? `${column.label}: ` : "";
401
303
  return html`
402
- <div class="cell-content" aria-label="${ariaLabel}">
403
- ${[
404
- mobileLabel,
405
- __privateMethod(this, _GdsTable_instances, renderCell_fn).call(this, cell?.lead, row),
406
- processedValue,
407
- __privateMethod(this, _GdsTable_instances, renderCell_fn).call(this, cell?.trail, row)
408
- ]}
304
+ <div
305
+ class="cell-content"
306
+ aria-label=${ifDefined(isMobile ? column.label : void 0)}
307
+ >
308
+ ${isMobile ? __privateMethod(this, _GdsTable_instances, renderMobileLabel_fn).call(this, column) : null} ${content}
409
309
  </div>
410
310
  `;
411
311
  };
@@ -530,11 +430,16 @@ renderActionsHeader_fn = function() {
530
430
  const label = this.actions.label || msg("Actions");
531
431
  const classes = classMap({
532
432
  actions: true,
433
+ sticky: Boolean(this.actions.sticky),
434
+ wrap: Boolean(this.actions.width),
533
435
  [`align-${this.actions.align}`]: !!this.actions.align,
534
436
  [`justify-${this.actions.justify}`]: !!this.actions.justify
535
437
  });
438
+ const style = styleMap({
439
+ "--cell-width": this.actions.width
440
+ });
536
441
  return html`
537
- <th class="${classes}">
442
+ <th class="${classes}" style=${style}>
538
443
  <div class="column-header">
539
444
  <div class="column-label">${label}</div>
540
445
  </div>
@@ -549,7 +454,8 @@ renderSelectableHeader_fn = function() {
549
454
  checked: __privateGet(this, _GdsTable_instances, isAllSelected_get),
550
455
  indeterminate: __privateGet(this, _GdsTable_instances, isPartialSelection_get),
551
456
  ariaLabel: msg("Select all rows"),
552
- onToggle: () => __privateMethod(this, _GdsTable_instances, handleSelectAll_fn).call(this, {})
457
+ onToggle: () => __privateMethod(this, _GdsTable_instances, handleSelectAll_fn).call(this, {}),
458
+ skip: this.disableSelectAll
553
459
  })}
554
460
  </th>
555
461
  `;
@@ -570,7 +476,7 @@ renderTableHeader_fn = function() {
570
476
  </thead>
571
477
  `;
572
478
  };
573
- renderTableCell_fn = function(row, column) {
479
+ renderTableCell_fn = function(row, column, index) {
574
480
  const classes = classMap({
575
481
  [`align-${column.align}`]: !!column.align,
576
482
  [`justify-${column.justify}`]: !!column.justify,
@@ -581,7 +487,7 @@ renderTableCell_fn = function(row, column) {
581
487
  });
582
488
  return html`
583
489
  <td style=${style} class=${classes}>
584
- ${__privateMethod(this, _GdsTable_instances, renderCellContent_fn).call(this, row, column)}
490
+ ${__privateMethod(this, _GdsTable_instances, renderCellContent_fn).call(this, row, column, index)}
585
491
  </td>
586
492
  `;
587
493
  };
@@ -601,8 +507,8 @@ renderSelectableCell_fn = function(index) {
601
507
  </td>
602
508
  `;
603
509
  };
604
- renderRowCells_fn = function(row) {
605
- return this.columns.filter((column) => this._view.visibleColumns.has(column.key)).map((column) => __privateMethod(this, _GdsTable_instances, renderTableCell_fn).call(this, row, column));
510
+ renderRowCells_fn = function(row, index) {
511
+ return this.columns.filter((column) => this._view.visibleColumns.has(column.key)).map((column) => __privateMethod(this, _GdsTable_instances, renderTableCell_fn).call(this, row, column, index));
606
512
  };
607
513
  renderActionsCell_fn = function(row, index) {
608
514
  if (!this.actions) return null;
@@ -613,15 +519,22 @@ renderActionsCell_fn = function(row, index) {
613
519
  </td>
614
520
  `;
615
521
  }
616
- const content = __privateMethod(this, _GdsTable_instances, renderCell_fn).call(this, this.actions.cell, row);
522
+ const rowKey = __privateMethod(this, _GdsTable_instances, getRowKey_fn).call(this, row, index);
617
523
  const classes = classMap({
618
524
  "actions-cell": true,
525
+ sticky: Boolean(this.actions.sticky),
526
+ wrap: Boolean(this.actions.width),
619
527
  [`align-${this.actions.align}`]: !!this.actions.align,
620
528
  [`justify-${this.actions.justify}`]: !!this.actions.justify
621
529
  });
530
+ const style = styleMap({
531
+ "--cell-width": this.actions.width
532
+ });
622
533
  return html`
623
- <td class="${classes}">
624
- <div class="cell-content">${content}</div>
534
+ <td class="${classes}" style=${style}>
535
+ <div class="cell-content">
536
+ ${__privateMethod(this, _GdsTable_instances, renderSlotElement_fn).call(this, "actions", rowKey, "main")}
537
+ </div>
625
538
  </td>
626
539
  `;
627
540
  };
@@ -635,7 +548,7 @@ renderTableRow_fn = function(row, index) {
635
548
  >
636
549
  ${[
637
550
  __privateMethod(this, _GdsTable_instances, renderSelectableCell_fn).call(this, index),
638
- __privateMethod(this, _GdsTable_instances, renderRowCells_fn).call(this, row),
551
+ __privateMethod(this, _GdsTable_instances, renderRowCells_fn).call(this, row, index),
639
552
  __privateMethod(this, _GdsTable_instances, renderActionsCell_fn).call(this, row, index)
640
553
  ]}
641
554
  </tr>
@@ -646,8 +559,10 @@ renderCheckbox_fn = function({
646
559
  indeterminate = false,
647
560
  disabled = false,
648
561
  ariaLabel,
649
- onToggle
562
+ onToggle,
563
+ skip = false
650
564
  }) {
565
+ if (skip) return null;
651
566
  const toggle = (e) => {
652
567
  e.stopPropagation();
653
568
  if (disabled) return;
@@ -737,6 +652,67 @@ renderTableBody_fn = function() {
737
652
  </tbody>
738
653
  `;
739
654
  };
655
+ renderTableFoot_fn = function() {
656
+ if (!this.tfoot) return null;
657
+ const label = this.tfoot.label;
658
+ const visibleColumns = this.columns.filter(
659
+ (column) => this._view.visibleColumns.has(column.key)
660
+ );
661
+ const classes = classMap({
662
+ tablefoot: true,
663
+ sticky: Boolean(this.tfoot.sticky)
664
+ });
665
+ return html`
666
+ <tfoot class=${classes}>
667
+ <tr>
668
+ ${when(this.selectable, () => html`<td class="checkbox-cell"></td>`)}
669
+ ${visibleColumns.map((column, i) => {
670
+ const cellClasses = classMap({
671
+ "tablefoot-cell": true,
672
+ "tablefoot-label-cell": i === 0,
673
+ [`align-${column.align}`]: !!column.align,
674
+ [`justify-${column.justify}`]: !!column.justify,
675
+ wrap: Boolean(column.width)
676
+ });
677
+ const style = styleMap({
678
+ "--cell-width": column.width
679
+ });
680
+ if (i === 0 && label) {
681
+ return html`
682
+ <th scope="row" class=${cellClasses} style=${style}>
683
+ <div class="cell-content">
684
+ <span class="tablefoot-label">${label}</span>
685
+ <slot name="tfoot:${column.key}"></slot>
686
+ </div>
687
+ </th>
688
+ `;
689
+ }
690
+ return html`
691
+ <td class=${cellClasses} style=${style}>
692
+ <div class="cell-content">
693
+ <slot name="tfoot:${column.key}"></slot>
694
+ </div>
695
+ </td>
696
+ `;
697
+ })}
698
+ ${when(this.actions, () => {
699
+ const isObj = this.actions && typeof this.actions !== "function";
700
+ const stickyAction = isObj && this.actions.sticky;
701
+ const actionClasses = classMap({
702
+ "actions-cell": true,
703
+ "tablefoot-cell": true,
704
+ sticky: Boolean(stickyAction)
705
+ });
706
+ return html`<td class=${actionClasses}>
707
+ <div class="cell-content">
708
+ <slot name="tfoot:actions"></slot>
709
+ </div>
710
+ </td>`;
711
+ })}
712
+ </tr>
713
+ </tfoot>
714
+ `;
715
+ };
740
716
  renderTable_fn = function() {
741
717
  const CLASSES = classMap({
742
718
  responsive: this.responsive,
@@ -751,7 +727,7 @@ renderTable_fn = function() {
751
727
  variant="${this.variant}"
752
728
  padding="0"
753
729
  border-radius="m"
754
- border-width="0; s{5xs}"
730
+ border-width="${this.responsive ? "0; s{5xs}" : "5xs"}"
755
731
  class="table-card"
756
732
  >
757
733
  <div class=${CLASSES} tabindex="0">
@@ -760,6 +736,7 @@ renderTable_fn = function() {
760
736
  ${caption}
761
737
  </caption>
762
738
  ${__privateMethod(this, _GdsTable_instances, renderTableHeader_fn).call(this)} ${__privateMethod(this, _GdsTable_instances, renderTableBody_fn).call(this)}
739
+ ${__privateMethod(this, _GdsTable_instances, renderTableFoot_fn).call(this)}
763
740
  </table>
764
741
  </div>
765
742
  </gds-card>
@@ -822,18 +799,20 @@ renderFooter_fn = function() {
822
799
  const end = Math.min(this._view.page * this._view.rows, this._total);
823
800
  const summaryString = `${start}\u2013${end} ${msg("of")} ${this._total}`;
824
801
  return html`
825
- <gds-pagination
826
- .page=${this._view.page}
827
- .rows=${this._view.rows}
828
- .options=${this.options}
829
- .total=${this._total}
830
- .density=${this.density}
831
- .label=${summaryString}
832
- @gds-page-change=${__privateMethod(this, _GdsTable_instances, handlePageChange_fn)}
833
- @gds-rows-change=${__privateMethod(this, _GdsTable_instances, handlePageSizeChange_fn)}
834
- width="100%"
835
- >
836
- </gds-pagination>
802
+ <slot name="footer">
803
+ <gds-pagination
804
+ .page=${this._view.page}
805
+ .rows=${this._view.rows}
806
+ .options=${this.options}
807
+ .total=${this._total}
808
+ .density=${this.density}
809
+ .label=${summaryString}
810
+ @gds-page-change=${__privateMethod(this, _GdsTable_instances, handlePageChange_fn)}
811
+ @gds-rows-change=${__privateMethod(this, _GdsTable_instances, handlePageSizeChange_fn)}
812
+ width="100%"
813
+ >
814
+ </gds-pagination>
815
+ </slot>
837
816
  `;
838
817
  };
839
818
  renderHeadline_fn = function() {
@@ -1003,14 +982,21 @@ initializeScrollTracking_fn = function() {
1003
982
  /**
1004
983
  * Updates CSS classes based on vertical scroll position.
1005
984
  * Adds 'scrolled' class when scrolled down from top.
985
+ * Adds 'scrolled-bottom' class when not scrolled to the very bottom.
1006
986
  */
1007
987
  updateVerticalScrollState_fn = function(container) {
1008
- const { scrollTop } = container;
988
+ const { scrollTop, scrollHeight, clientHeight } = container;
989
+ const maxScrollTop = scrollHeight - clientHeight;
1009
990
  if (scrollTop > 0) {
1010
991
  container.classList.add("scrolled");
1011
992
  } else {
1012
993
  container.classList.remove("scrolled");
1013
994
  }
995
+ if (scrollTop < maxScrollTop - 1) {
996
+ container.classList.add("scrolled-bottom");
997
+ } else {
998
+ container.classList.remove("scrolled-bottom");
999
+ }
1014
1000
  };
1015
1001
  /**
1016
1002
  * Updates CSS classes based on horizontal scroll position.
@@ -1072,6 +1058,13 @@ __decorateClass([
1072
1058
  __decorateClass([
1073
1059
  property({ type: Boolean, reflect: false })
1074
1060
  ], GdsTable.prototype, "selectable", 2);
1061
+ __decorateClass([
1062
+ property({
1063
+ attribute: "disable-select-all",
1064
+ type: Boolean,
1065
+ reflect: false
1066
+ })
1067
+ ], GdsTable.prototype, "disableSelectAll", 2);
1075
1068
  __decorateClass([
1076
1069
  property({ type: Boolean, reflect: false })
1077
1070
  ], GdsTable.prototype, "responsive", 2);
@@ -1093,6 +1086,9 @@ __decorateClass([
1093
1086
  __decorateClass([
1094
1087
  property({ type: Boolean, reflect: false })
1095
1088
  ], GdsTable.prototype, "nocache", 2);
1089
+ __decorateClass([
1090
+ property({ type: Object })
1091
+ ], GdsTable.prototype, "tfoot", 2);
1096
1092
  __decorateClass([
1097
1093
  property()
1098
1094
  ], GdsTable.prototype, "dataLoadKey", 2);
@@ -1137,6 +1133,12 @@ __decorateClass([
1137
1133
  watch("dataLoadKey"),
1138
1134
  watch("data")
1139
1135
  ], GdsTable.prototype, "_onDataChange", 1);
1136
+ __decorateClass([
1137
+ watch("page", { waitUntilFirstUpdate: true })
1138
+ ], GdsTable.prototype, "_onPageChange", 1);
1139
+ __decorateClass([
1140
+ watch("rows", { waitUntilFirstUpdate: true })
1141
+ ], GdsTable.prototype, "_onRowsChange", 1);
1140
1142
  __decorateClass([
1141
1143
  watch("columns")
1142
1144
  ], GdsTable.prototype, "_onColumnsChange", 1);
@@ -1,53 +1,39 @@
1
- import { TableColumn, TableRequest, TableResponse } from './table.types';
2
- interface UserData {
3
- id: number;
4
- name: string;
5
- email: string;
6
- role: 'Admin' | 'User' | 'Editor';
7
- status: 'Active' | 'Inactive';
8
- amount: number;
9
- account: string;
10
- lastLogin: string;
11
- avatarUrl?: string;
12
- department?: string;
13
- download?: string;
14
- }
15
- interface FeedbackData {
16
- id: number;
17
- name: string;
18
- email: string;
19
- feedback: string;
20
- notes: string;
21
- status: 'Active' | 'Inactive';
22
- department: string;
23
- }
1
+ import { TemplateResult } from 'lit';
2
+ import type { TableActions, TableColumn, TableRequest, TableResponse, TableTfoot } from './table.types';
24
3
  export declare const Users: {
25
4
  Columns: TableColumn[];
26
- Actions: {
27
- label: string;
28
- justify: string;
29
- cell: {
30
- type: string;
31
- items: ({
32
- label: (row: UserData) => "Activate" | "Deactivate";
33
- divider?: undefined;
34
- } | {
35
- label: string;
36
- divider?: undefined;
37
- } | {
38
- divider: boolean;
39
- label: string;
40
- })[];
41
- };
42
- };
43
- Data: (request: TableRequest) => Promise<TableResponse<UserData>>;
5
+ Actions: TableActions;
6
+ Tfoot: TableTfoot;
7
+ Data: (request: TableRequest) => Promise<TableResponse<any>>;
8
+ /**
9
+ * Generates slot content for the given rows (current page).
10
+ * Creates per-row slot elements using `columnKey:rowKey:slotId` convention.
11
+ *
12
+ * Used with Lit's `render()` to update table light DOM on each data load:
13
+ * ```ts
14
+ * @gds-table-data-loaded=${(e) => render(Users.SlotContent(e.detail.rows), table)}
15
+ * ```
16
+ */
17
+ SlotContent: (rows: any[]) => TemplateResult;
18
+ /**
19
+ * Generates tfoot slot content for the footer row.
20
+ * Receives all rows on the page and computes aggregations.
21
+ *
22
+ * Slot naming: `tfoot:{columnKey}`
23
+ */
24
+ TfootSlotContent: (rows: any[]) => TemplateResult;
44
25
  };
45
26
  export declare const Feedback: {
46
27
  Columns: TableColumn[];
47
- MultipleActions: any;
48
- ActionLink: any;
49
- ActionButton: any;
50
- ActionContextMenu: any;
51
- Data: (request: TableRequest) => Promise<TableResponse<FeedbackData>>;
28
+ Data: (request: TableRequest) => Promise<TableResponse<any>>;
29
+ };
30
+ export declare const Actions: {
31
+ Columns: TableColumn[];
32
+ MultipleActions: TableActions;
33
+ MultipleActionsSlotContent: (rows: any[]) => TemplateResult;
34
+ ActionLink: TableActions;
35
+ ActionLinkSlotContent: (rows: any[]) => TemplateResult;
36
+ ActionContextMenu: TableActions;
37
+ ActionContextMenuSlotContent: (rows: any[]) => TemplateResult;
38
+ Data: (request: TableRequest) => Promise<TableResponse<any>>;
52
39
  };
53
- export {};