@triptyk/ember-yeti-table 3.0.0 → 3.0.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 (130) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +9 -115
  3. package/declarations/components/yeti-table/body.d.ts +32 -0
  4. package/declarations/components/yeti-table/body.d.ts.map +1 -0
  5. package/declarations/components/yeti-table/header.d.ts +33 -0
  6. package/declarations/components/yeti-table/header.d.ts.map +1 -0
  7. package/declarations/components/yeti-table/pagination.d.ts +40 -0
  8. package/declarations/components/yeti-table/pagination.d.ts.map +1 -0
  9. package/declarations/components/yeti-table/table.d.ts +21 -0
  10. package/declarations/components/yeti-table/table.d.ts.map +1 -0
  11. package/declarations/components/yeti-table/tbody/row/cell.d.ts +44 -0
  12. package/declarations/components/yeti-table/tbody/row/cell.d.ts.map +1 -0
  13. package/declarations/components/yeti-table/tbody/row.d.ts +37 -0
  14. package/declarations/components/yeti-table/tbody/row.d.ts.map +1 -0
  15. package/declarations/components/yeti-table/tbody.d.ts +29 -0
  16. package/declarations/components/yeti-table/tbody.d.ts.map +1 -0
  17. package/declarations/components/yeti-table/tfoot/row/cell.d.ts +40 -0
  18. package/declarations/components/yeti-table/tfoot/row/cell.d.ts.map +1 -0
  19. package/declarations/components/yeti-table/tfoot/row.d.ts +37 -0
  20. package/declarations/components/yeti-table/tfoot/row.d.ts.map +1 -0
  21. package/declarations/components/yeti-table/tfoot.d.ts +27 -0
  22. package/declarations/components/yeti-table/tfoot.d.ts.map +1 -0
  23. package/declarations/components/yeti-table/thead/row/cell.d.ts +54 -0
  24. package/declarations/components/yeti-table/thead/row/cell.d.ts.map +1 -0
  25. package/declarations/components/yeti-table/thead/row/column.d.ts +69 -0
  26. package/declarations/components/yeti-table/thead/row/column.d.ts.map +1 -0
  27. package/declarations/components/yeti-table/thead/row.d.ts +55 -0
  28. package/declarations/components/yeti-table/thead/row.d.ts.map +1 -0
  29. package/declarations/components/yeti-table/thead.d.ts +34 -0
  30. package/declarations/components/yeti-table/thead.d.ts.map +1 -0
  31. package/declarations/components/yeti-table.d.ts +107 -0
  32. package/declarations/components/yeti-table.d.ts.map +1 -0
  33. package/declarations/index.d.ts +1 -0
  34. package/declarations/index.d.ts.map +1 -0
  35. package/declarations/template-registry.d.ts +1 -0
  36. package/declarations/template-registry.d.ts.map +1 -0
  37. package/declarations/themes/default-theme.d.ts +3 -27
  38. package/declarations/themes/default-theme.d.ts.map +1 -1
  39. package/declarations/types.d.ts +82 -0
  40. package/declarations/types.d.ts.map +1 -0
  41. package/declarations/utils/create-regex.d.ts +1 -1
  42. package/declarations/utils/create-regex.d.ts.map +1 -1
  43. package/declarations/utils/filtering-utils.d.ts +2 -4
  44. package/declarations/utils/filtering-utils.d.ts.map +1 -1
  45. package/declarations/utils/sorting-utils.d.ts +6 -15
  46. package/declarations/utils/sorting-utils.d.ts.map +1 -1
  47. package/dist/components/yeti-table/body.js +19 -14
  48. package/dist/components/yeti-table/body.js.map +1 -1
  49. package/dist/components/yeti-table/header.js +10 -10
  50. package/dist/components/yeti-table/header.js.map +1 -1
  51. package/dist/components/yeti-table/pagination.js +14 -44
  52. package/dist/components/yeti-table/pagination.js.map +1 -1
  53. package/dist/components/yeti-table/table.js +1 -23
  54. package/dist/components/yeti-table/table.js.map +1 -1
  55. package/dist/components/yeti-table/tbody/row/cell.js +12 -12
  56. package/dist/components/yeti-table/tbody/row/cell.js.map +1 -1
  57. package/dist/components/yeti-table/tbody/row.js +15 -21
  58. package/dist/components/yeti-table/tbody/row.js.map +1 -1
  59. package/dist/components/yeti-table/tbody.js +1 -0
  60. package/dist/components/yeti-table/tbody.js.map +1 -1
  61. package/dist/components/yeti-table/tfoot/row/cell.js +9 -9
  62. package/dist/components/yeti-table/tfoot/row/cell.js.map +1 -1
  63. package/dist/components/yeti-table/tfoot/row.js +11 -11
  64. package/dist/components/yeti-table/tfoot/row.js.map +1 -1
  65. package/dist/components/yeti-table/tfoot.js +1 -0
  66. package/dist/components/yeti-table/tfoot.js.map +1 -1
  67. package/dist/components/yeti-table/thead/row/cell.js +11 -8
  68. package/dist/components/yeti-table/thead/row/cell.js.map +1 -1
  69. package/dist/components/yeti-table/thead/row/column.js +27 -128
  70. package/dist/components/yeti-table/thead/row/column.js.map +1 -1
  71. package/dist/components/yeti-table/thead/row.js +15 -15
  72. package/dist/components/yeti-table/thead/row.js.map +1 -1
  73. package/dist/components/yeti-table/thead.js +3 -22
  74. package/dist/components/yeti-table/thead.js.map +1 -1
  75. package/dist/components/yeti-table.js +99 -303
  76. package/dist/components/yeti-table.js.map +1 -1
  77. package/dist/index.js +2 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/template-registry.js +2 -0
  80. package/dist/template-registry.js.map +1 -0
  81. package/dist/themes/default-theme.js +3 -2
  82. package/dist/themes/default-theme.js.map +1 -1
  83. package/dist/types.js +2 -0
  84. package/dist/types.js.map +1 -0
  85. package/dist/utils/create-regex.js +6 -6
  86. package/dist/utils/create-regex.js.map +1 -1
  87. package/dist/utils/filtering-utils.js +20 -8
  88. package/dist/utils/filtering-utils.js.map +1 -1
  89. package/dist/utils/sorting-utils.js +13 -18
  90. package/dist/utils/sorting-utils.js.map +1 -1
  91. package/package.json +37 -16
  92. package/src/components/yeti-table/{body.gjs → body.gts} +49 -45
  93. package/src/components/yeti-table/header.gts +67 -0
  94. package/src/components/yeti-table/pagination.gts +118 -0
  95. package/src/components/yeti-table/table.gts +27 -0
  96. package/src/components/yeti-table/tbody/row/{cell.gjs → cell.gts} +38 -19
  97. package/src/components/yeti-table/tbody/row.gts +76 -0
  98. package/src/components/yeti-table/tbody.gts +53 -0
  99. package/src/components/yeti-table/tfoot/row/cell.gts +64 -0
  100. package/src/components/yeti-table/tfoot/row.gts +59 -0
  101. package/src/components/yeti-table/tfoot.gts +41 -0
  102. package/src/components/yeti-table/thead/row/{cell.gjs → cell.gts} +36 -13
  103. package/src/components/yeti-table/thead/row/column.gts +177 -0
  104. package/src/components/yeti-table/thead/row.gts +105 -0
  105. package/src/components/yeti-table/thead.gts +65 -0
  106. package/src/components/yeti-table.gts +629 -0
  107. package/src/template-registry.ts +10 -0
  108. package/src/themes/{default-theme.js → default-theme.ts} +5 -1
  109. package/src/types.ts +94 -0
  110. package/src/utils/{create-regex.js → create-regex.ts} +10 -10
  111. package/src/utils/filtering-utils.ts +91 -0
  112. package/src/utils/{sorting-utils.js → sorting-utils.ts} +35 -26
  113. package/dist/_app_/themes/default-theme.js +0 -1
  114. package/dist/_app_/utils/create-regex.js +0 -1
  115. package/dist/_app_/utils/filtering-utils.js +0 -1
  116. package/dist/_app_/utils/sorting-utils.js +0 -1
  117. package/src/components/yeti-table/header.gjs +0 -54
  118. package/src/components/yeti-table/pagination.gjs +0 -155
  119. package/src/components/yeti-table/table.gjs +0 -34
  120. package/src/components/yeti-table/tbody/row.gjs +0 -89
  121. package/src/components/yeti-table/tbody.gjs +0 -55
  122. package/src/components/yeti-table/tfoot/row/cell.gjs +0 -45
  123. package/src/components/yeti-table/tfoot/row.gjs +0 -44
  124. package/src/components/yeti-table/tfoot.gjs +0 -33
  125. package/src/components/yeti-table/thead/row/column.gjs +0 -260
  126. package/src/components/yeti-table/thead/row.gjs +0 -71
  127. package/src/components/yeti-table/thead.gjs +0 -45
  128. package/src/components/yeti-table.gjs +0 -780
  129. package/src/utils/filtering-utils.js +0 -75
  130. /package/src/{.gitkeep → index.ts} +0 -0
@@ -1,44 +1,60 @@
1
1
  import { action } from '@ember/object';
2
-
3
2
  import Component from '@glimmer/component';
4
3
 
4
+ import { fn, get, hash } from '@ember/helper';
5
+
6
+ import type { WithBoundArgs } from '@glint/template';
7
+
8
+ import TBodyRow from './tbody/row.gts';
9
+ import type {
10
+ ColumnDefinition,
11
+ Row,
12
+ RowClickHandler,
13
+ Theme,
14
+ } from '../../types.ts';
15
+
5
16
  /**
6
17
  Renders a `<tbody>` element and yields the row component, row data and index.
7
- ```hbs
8
- <table.body as |body person index|>
9
- <body.row as |row|>
10
- <row.cell>
11
- {{person.firstName}} #{{index}}
12
- </row.cell>
13
- <row.cell>
14
- {{person.lastName}}
15
- </row.cell>
16
- <row.cell>
17
- {{person.points}}
18
- </row.cell>
19
- </body.row>
20
- </table.body>
21
- ```
22
- It can also be used as a blockless component to let yeti table automatically
23
- unroll thee rows for you, based on the `@prop` arguments you passed in to the
24
- column definition components.
25
- ```hbs
26
- <table.body/>
27
- ```
28
- Remember that this component's block will be rendered once per each item in the `@data` array.
29
18
 
30
19
  @class Body
31
- @yield {object} body
32
- @yield {Component} body.row - the row component
33
- @yield {Object} rowData - one item in the data array
34
- @yield {number} index
35
20
  */
36
21
 
37
- // template imports
38
- import { fn, get, hash } from '@ember/helper';
39
- import TBodyRow from './tbody/row.gjs';
22
+ export interface BodySignature {
23
+ Element: HTMLTableSectionElement;
24
+ Args: {
25
+ theme?: Theme;
26
+ data?: Row[];
27
+ columns?: ColumnDefinition[];
28
+ onRowClick?: RowClickHandler;
29
+ };
30
+ Blocks: {
31
+ default: [
32
+ { row: WithBoundArgs<typeof TBodyRow, 'theme' | 'onClick' | 'columns'> },
33
+ Row,
34
+ number,
35
+ ];
36
+ };
37
+ }
38
+
39
+ export default class Body extends Component<BodySignature> {
40
+ @action
41
+ handleRowClick(rowData: Row): void {
42
+ this.args.onRowClick?.(rowData);
43
+ }
44
+
45
+ asContent = (value: unknown): string => {
46
+ if (value == null) return '';
47
+ if (typeof value === 'string') return value;
48
+ if (typeof value === 'number' || typeof value === 'boolean') {
49
+ return String(value);
50
+ }
51
+ try {
52
+ return JSON.stringify(value);
53
+ } catch {
54
+ return '';
55
+ }
56
+ };
40
57
 
41
- export default class Body extends Component {
42
58
  <template>
43
59
  <tbody class={{@theme.tbody}} ...attributes>
44
60
  {{#if (has-block)}}
@@ -68,9 +84,9 @@ export default class Body extends Component {
68
84
  {{#each @columns as |column|}}
69
85
  <row.cell @class={{column.columnClass}}>
70
86
  {{#if column.prop}}
71
- {{get rowData column.prop}}
87
+ {{this.asContent (get rowData column.prop)}}
72
88
  {{else}}
73
- {{rowData}}
89
+ {{this.asContent rowData}}
74
90
  {{/if}}
75
91
  </row.cell>
76
92
  {{/each}}
@@ -79,16 +95,4 @@ export default class Body extends Component {
79
95
  {{/if}}
80
96
  </tbody>
81
97
  </template>
82
- /**
83
- * Adds a click action to each row, called with the clicked row's data as an argument.
84
- * Can be used with both the blockless and block invocations.
85
- *
86
- * @argument onRowClick
87
- * @type Function
88
- */
89
-
90
- @action
91
- handleRowClick(rowData) {
92
- this.args.onRowClick?.(rowData);
93
- }
94
98
  }
@@ -0,0 +1,67 @@
1
+ import { action } from '@ember/object';
2
+ import Component from '@glimmer/component';
3
+
4
+ import { hash } from '@ember/helper';
5
+
6
+ import type { WithBoundArgs } from '@glint/template';
7
+
8
+ import Column from './thead/row/column.gts';
9
+ import type { ColumnParent } from './thead/row/column.gts';
10
+ import type { ColumnDefinition, SortDirection, Theme } from '../../types.ts';
11
+
12
+ /**
13
+ Renders a `<thead>` element and yields the column component.
14
+
15
+ @class Header
16
+ */
17
+
18
+ export interface HeaderSignature {
19
+ Element: HTMLTableSectionElement;
20
+ Args: {
21
+ trClass?: string;
22
+ theme?: Theme;
23
+ sortable?: boolean;
24
+ sortSequence?: SortDirection[] | string;
25
+ columns?: ColumnDefinition[];
26
+ onColumnClick?: (column: Column, e: MouseEvent) => void;
27
+ parent?: ColumnParent;
28
+ };
29
+ Blocks: {
30
+ default: [
31
+ {
32
+ column: WithBoundArgs<
33
+ typeof Column,
34
+ 'sortable' | 'sortSequence' | 'onClick' | 'parent' | 'theme'
35
+ >;
36
+ },
37
+ ];
38
+ };
39
+ }
40
+
41
+ export default class Header extends Component<HeaderSignature> {
42
+ @action
43
+ onColumnClickHeader(column: Column, e: MouseEvent): void {
44
+ if (this.args.onColumnClick && column.sortable) {
45
+ this.args.onColumnClick(column, e);
46
+ }
47
+ }
48
+
49
+ <template>
50
+ <thead class={{@theme.thead}} ...attributes>
51
+ <tr class="{{@trClass}} {{@theme.theadRow}} {{@theme.row}}">
52
+ {{yield
53
+ (hash
54
+ column=(component
55
+ Column
56
+ sortable=@sortable
57
+ sortSequence=@sortSequence
58
+ onClick=this.onColumnClickHeader
59
+ parent=@parent
60
+ theme=@theme
61
+ )
62
+ )
63
+ }}
64
+ </tr>
65
+ </thead>
66
+ </template>
67
+ }
@@ -0,0 +1,118 @@
1
+ import { action } from '@ember/object';
2
+ import { helper } from '@ember/component/helper';
3
+ import Component from '@glimmer/component';
4
+ import { localCopy } from 'tracked-toolbox';
5
+
6
+ import { on } from '@ember/modifier';
7
+
8
+ import type { PaginationActions, PaginationData, Theme } from '../../types.ts';
9
+ import { uniqueId } from '@ember/helper';
10
+
11
+ /**
12
+ Simple pagination controls component that is included to help you get started quickly.
13
+
14
+ @class Pagination
15
+ */
16
+
17
+ export interface PaginationSignature {
18
+ Element: HTMLDivElement;
19
+ Args: {
20
+ theme?: Theme;
21
+ paginationData: PaginationData;
22
+ paginationActions: PaginationActions;
23
+ disabled?: boolean;
24
+ pageSizes?: number[];
25
+ showInfo?: boolean;
26
+ showPageSizeSelector?: boolean;
27
+ showButtons?: boolean;
28
+ };
29
+ Blocks: { default: [] };
30
+ }
31
+
32
+ export default class Pagination extends Component<PaginationSignature> {
33
+ isPaginationNumberSelected = helper(([number]: [number]) => {
34
+ return number === this.args.paginationData.pageSize;
35
+ });
36
+
37
+ get shouldDisablePrevious(): boolean {
38
+ return !!this.args.paginationData.isFirstPage || !!this.args.disabled;
39
+ }
40
+
41
+ get shouldDisableNext(): boolean {
42
+ return !!this.args.paginationData.isLastPage || !!this.args.disabled;
43
+ }
44
+
45
+ @localCopy('args.pageSizes', [10, 15, 20, 25])
46
+ pageSizes!: number[];
47
+
48
+ @localCopy('args.showInfo', true)
49
+ showInfo!: boolean;
50
+
51
+ @localCopy('args.showPageSizeSelector', true)
52
+ showPageSizeSelector!: boolean;
53
+
54
+ @localCopy('args.showButtons', true)
55
+ showButtons!: boolean;
56
+
57
+ @action
58
+ changePageSize(ev: Event): void {
59
+ const target = ev.target as HTMLSelectElement;
60
+ this.args.paginationActions.changePageSize(target.value);
61
+ }
62
+
63
+ <template>
64
+ <div class={{@theme.pagination.controls}} ...attributes>
65
+ {{#if this.showInfo}}
66
+ <div class={{@theme.pagination.info}}>
67
+ Showing
68
+ {{@paginationData.pageStart}}
69
+ to
70
+ {{@paginationData.pageEnd}}
71
+ of
72
+ {{@paginationData.totalRows}}
73
+ entries
74
+ </div>
75
+ {{/if}}
76
+
77
+ {{#if this.showPageSizeSelector}}
78
+ <div class={{@theme.pagination.pageSize}}>
79
+ {{#let (uniqueId) as |selectId|}}
80
+ <label for="page-size-select-{{selectId}}">Rows per page:</label>
81
+ <select
82
+ id="page-size-select-{{selectId}}"
83
+ disabled={{@disabled}}
84
+ {{on "change" this.changePageSize}}
85
+ >
86
+ {{#each this.pageSizes as |pageSize|}}
87
+ <option
88
+ value={{pageSize}}
89
+ selected={{this.isPaginationNumberSelected pageSize}}
90
+ >{{pageSize}}</option>
91
+ {{/each}}
92
+ </select>
93
+ {{/let}}
94
+ </div>
95
+ {{/if}}
96
+
97
+ {{#if this.showButtons}}
98
+ <button
99
+ type="button"
100
+ class={{@theme.pagination.previous}}
101
+ disabled={{this.shouldDisablePrevious}}
102
+ {{on "click" @paginationActions.previousPage}}
103
+ >
104
+ Previous
105
+ </button>
106
+
107
+ <button
108
+ type="button"
109
+ class={{@theme.pagination.next}}
110
+ disabled={{this.shouldDisableNext}}
111
+ {{on "click" @paginationActions.nextPage}}
112
+ >
113
+ Next
114
+ </button>
115
+ {{/if}}
116
+ </div>
117
+ </template>
118
+ }
@@ -0,0 +1,27 @@
1
+ import type { TemplateOnlyComponent } from '@ember/component/template-only';
2
+
3
+ import type { Theme } from '../../types.ts';
4
+
5
+ /**
6
+ A simple component that just renders the `<table>` element with the correct
7
+ theme classes.
8
+
9
+ @class Table
10
+ */
11
+
12
+ export interface TableSignature {
13
+ Element: HTMLTableElement;
14
+ Args: {
15
+ theme?: Theme;
16
+ parent?: unknown;
17
+ };
18
+ Blocks: { default: [] };
19
+ }
20
+
21
+ const Table: TemplateOnlyComponent<TableSignature> = <template>
22
+ <table class={{@theme.table}} ...attributes>
23
+ {{yield}}
24
+ </table>
25
+ </template>;
26
+
27
+ export default Table;
@@ -1,5 +1,10 @@
1
1
  import Component from '@glimmer/component';
2
2
  import { tracked } from '@glimmer/tracking';
3
+ import type Owner from '@ember/owner';
4
+
5
+ import { hash } from '@ember/helper';
6
+
7
+ import type { ColumnDefinition, Theme } from '../../../../types.ts';
3
8
 
4
9
  /**
5
10
  @class TBodyCell
@@ -18,34 +23,48 @@ import { tracked } from '@glimmer/tracking';
18
23
  ```
19
24
  */
20
25
 
21
- import { hash } from '@ember/helper';
26
+ export interface TBodyCellParent {
27
+ registerCell(cell: TBodyCell): number;
28
+ unregisterCell(cell: TBodyCell): void;
29
+ }
22
30
 
23
- export default class TBodyCell extends Component {
24
- <template>
25
- {{#if this.column.visible}}
26
- <td
27
- class="{{@class}} {{this.column.columnClass}} {{@theme.tbodyCell}}"
28
- ...attributes
29
- >
30
- {{yield (hash prop=this.column.prop)}}
31
- </td>
32
- {{/if}}
33
- </template>
31
+ export interface TBodyCellSignature {
32
+ Element: HTMLTableCellElement;
33
+ Args: {
34
+ class?: string;
35
+ theme?: Theme;
36
+ parent?: TBodyCellParent;
37
+ columns?: ColumnDefinition[];
38
+ };
39
+ Blocks: { default: [{ prop: string | undefined }] };
40
+ }
34
41
 
42
+ export default class TBodyCell extends Component<TBodyCellSignature> {
35
43
  @tracked
36
- index;
44
+ index: number | undefined;
37
45
 
38
- get column() {
39
- return this.args.columns[this.index] || {};
46
+ get column(): ColumnDefinition {
47
+ return this.args.columns?.[this.index ?? -1] ?? {};
40
48
  }
41
49
 
42
- constructor() {
43
- super(...arguments);
50
+ constructor(owner: Owner, args: TBodyCellSignature['Args']) {
51
+ super(owner, args);
44
52
  this.index = this.args.parent?.registerCell(this);
45
53
  }
46
54
 
47
- willDestroy() {
48
- super.willDestroy(...arguments);
55
+ willDestroy(): void {
56
+ super.willDestroy();
49
57
  this.args.parent?.unregisterCell(this);
50
58
  }
59
+
60
+ <template>
61
+ {{#if this.column.visible}}
62
+ <td
63
+ class="{{@class}} {{this.column.columnClass}} {{@theme.tbodyCell}}"
64
+ ...attributes
65
+ >
66
+ {{yield (hash prop=this.column.prop)}}
67
+ </td>
68
+ {{/if}}
69
+ </template>
51
70
  }
@@ -0,0 +1,76 @@
1
+ import { action } from '@ember/object';
2
+ import Component from '@glimmer/component';
3
+
4
+ import { hash } from '@ember/helper';
5
+ import { on } from '@ember/modifier';
6
+
7
+ import type { WithBoundArgs } from '@glint/template';
8
+
9
+ import Cell from './row/cell.gts';
10
+ import type {
11
+ ColumnDefinition,
12
+ RowClickHandler,
13
+ Theme,
14
+ } from '../../../types.ts';
15
+
16
+ /**
17
+ Renders a `<tr>` element and yields the cell component.
18
+
19
+ @class TBodyRow
20
+ @yield {object} row
21
+ @yield {Component} row.cell - the cell component
22
+ */
23
+
24
+ interface TBodyCellLike {
25
+ index?: number;
26
+ }
27
+
28
+ export interface TBodyRowSignature {
29
+ Element: HTMLTableRowElement;
30
+ Args: {
31
+ theme?: Theme;
32
+ columns?: ColumnDefinition[];
33
+ onClick?: RowClickHandler;
34
+ };
35
+ Blocks: {
36
+ default: [
37
+ { cell: WithBoundArgs<typeof Cell, 'theme' | 'parent' | 'columns'> },
38
+ ];
39
+ };
40
+ }
41
+
42
+ export default class TBodyRow extends Component<TBodyRowSignature> {
43
+ cells: TBodyCellLike[] = [];
44
+
45
+ registerCell(cell: TBodyCellLike): number {
46
+ const index = this.cells.length;
47
+ this.cells.push(cell);
48
+ return index;
49
+ }
50
+
51
+ unregisterCell(cell: TBodyCellLike): void {
52
+ const cells = this.cells;
53
+ const index = cells.indexOf(cell);
54
+
55
+ cells.splice(index, 1);
56
+ }
57
+
58
+ @action
59
+ handleClick(event: MouseEvent): void {
60
+ this.args.onClick?.(event);
61
+ }
62
+
63
+ <template>
64
+ {{! template-lint-disable no-invalid-interactive }}
65
+ <tr
66
+ class="{{@theme.tbodyRow}} {{@theme.row}}"
67
+ {{on "click" this.handleClick}}
68
+ role={{if @onClick "button"}}
69
+ ...attributes
70
+ >
71
+ {{yield
72
+ (hash cell=(component Cell theme=@theme parent=this columns=@columns))
73
+ }}
74
+ </tr>
75
+ </template>
76
+ }
@@ -0,0 +1,53 @@
1
+ import Component from '@glimmer/component';
2
+
3
+ import { hash } from '@ember/helper';
4
+
5
+ import type { WithBoundArgs } from '@glint/template';
6
+
7
+ import TBodyRow from './tbody/row.gts';
8
+ import type {
9
+ ColumnDefinition,
10
+ Row,
11
+ RowClickHandler,
12
+ Theme,
13
+ } from '../../types.ts';
14
+
15
+ /**
16
+ Renders a `<tbody>` element and yields the row component and data. You must iterate each row.
17
+
18
+ @class TBody
19
+ */
20
+
21
+ export interface TBodySignature {
22
+ Element: HTMLTableSectionElement;
23
+ Args: {
24
+ theme?: Theme;
25
+ data?: Row[];
26
+ columns?: ColumnDefinition[];
27
+ onRowClick?: RowClickHandler;
28
+ };
29
+ Blocks: {
30
+ default: [
31
+ {
32
+ row: WithBoundArgs<typeof TBodyRow, 'theme' | 'onClick' | 'columns'>;
33
+ },
34
+ Row[] | undefined,
35
+ ];
36
+ };
37
+ }
38
+
39
+ // eslint-disable-next-line ember/no-empty-glimmer-component-classes
40
+ export default class TBody extends Component<TBodySignature> {
41
+ <template>
42
+ <tbody class={{@theme.tbody}} ...attributes>
43
+ {{yield
44
+ (hash
45
+ row=(component
46
+ TBodyRow theme=@theme onClick=@onRowClick columns=@columns
47
+ )
48
+ )
49
+ @data
50
+ }}
51
+ </tbody>
52
+ </template>
53
+ }
@@ -0,0 +1,64 @@
1
+ import Component from '@glimmer/component';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import type Owner from '@ember/owner';
4
+
5
+ import type { ColumnDefinition, Theme } from '../../../../types.ts';
6
+
7
+ /**
8
+ Renders a `<td>` element and yields for the developer to supply content.
9
+
10
+ ```hbs
11
+ <table.tfoot as |foot|>
12
+ <foot.row as |row|>
13
+ <row.cell>
14
+ Footer content
15
+ </row.cell>
16
+ </foot.row>
17
+ </table.tfoot>
18
+ ```
19
+ @class TFootCell
20
+ */
21
+
22
+ export interface TFootCellParent {
23
+ registerCell(cell: TFootCell): number;
24
+ unregisterCell(cell: TFootCell): void;
25
+ }
26
+
27
+ export interface TFootCellSignature {
28
+ Element: HTMLTableCellElement;
29
+ Args: {
30
+ class?: string;
31
+ theme?: Theme;
32
+ parent?: TFootCellParent;
33
+ columns?: ColumnDefinition[];
34
+ };
35
+ Blocks: { default: [] };
36
+ }
37
+
38
+ export default class TFootCell extends Component<TFootCellSignature> {
39
+ @tracked
40
+ index: number | undefined;
41
+
42
+ get column(): ColumnDefinition | undefined {
43
+ return this.args.columns?.[this.index ?? -1];
44
+ }
45
+
46
+ constructor(owner: Owner, args: TFootCellSignature['Args']) {
47
+ super(owner, args);
48
+
49
+ this.index = this.args.parent?.registerCell(this);
50
+ }
51
+
52
+ willDestroy(): void {
53
+ super.willDestroy();
54
+ this.args.parent?.unregisterCell(this);
55
+ }
56
+
57
+ <template>
58
+ {{#if this.column.visible}}
59
+ <td class="{{@class}} {{@theme.tfootCell}}" ...attributes>
60
+ {{yield}}
61
+ </td>
62
+ {{/if}}
63
+ </template>
64
+ }
@@ -0,0 +1,59 @@
1
+ import Component from '@glimmer/component';
2
+
3
+ import { hash } from '@ember/helper';
4
+
5
+ import type { WithBoundArgs } from '@glint/template';
6
+
7
+ import Cell from './row/cell.gts';
8
+ import type { ColumnDefinition, Theme } from '../../../types.ts';
9
+
10
+ /**
11
+ Renders a `<tr>` element and yields cell component.
12
+
13
+ @class TFootRow
14
+ @yield {object} row
15
+ @yield {Component} row.cell
16
+ */
17
+
18
+ interface TFootCellLike {
19
+ index?: number;
20
+ }
21
+
22
+ export interface TFootRowSignature {
23
+ Element: HTMLTableRowElement;
24
+ Args: {
25
+ class?: string;
26
+ theme?: Theme;
27
+ columns?: ColumnDefinition[];
28
+ parent?: unknown;
29
+ };
30
+ Blocks: {
31
+ default: [
32
+ { cell: WithBoundArgs<typeof Cell, 'theme' | 'parent' | 'columns'> },
33
+ ];
34
+ };
35
+ }
36
+
37
+ export default class TFootRow extends Component<TFootRowSignature> {
38
+ cells: TFootCellLike[] = [];
39
+
40
+ registerCell(cell: TFootCellLike): number {
41
+ const index = this.cells.length;
42
+ this.cells.push(cell);
43
+ return index;
44
+ }
45
+
46
+ unregisterCell(cell: TFootCellLike): void {
47
+ const cells = this.cells;
48
+ const index = cells.indexOf(cell);
49
+ cells.splice(index, 1);
50
+ }
51
+
52
+ <template>
53
+ <tr class="{{@class}} {{@theme.tfootRow}} {{@theme.row}}" ...attributes>
54
+ {{yield
55
+ (hash cell=(component Cell theme=@theme parent=this columns=@columns))
56
+ }}
57
+ </tr>
58
+ </template>
59
+ }