katalyst-tables 2.6.0.beta → 3.0.0.beta1

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -1
  3. data/README.md +1 -23
  4. data/app/assets/stylesheets/katalyst/tables/_index.scss +1 -0
  5. data/app/assets/stylesheets/katalyst/tables/_ordinal.scss +38 -0
  6. data/app/assets/stylesheets/katalyst/tables/_table.scss +123 -0
  7. data/app/assets/stylesheets/katalyst/tables/typed-columns/_boolean.scss +4 -0
  8. data/app/assets/stylesheets/katalyst/tables/typed-columns/_currency.scss +5 -0
  9. data/app/assets/stylesheets/katalyst/tables/typed-columns/_date.scss +4 -0
  10. data/app/assets/stylesheets/katalyst/tables/typed-columns/_datetime.scss +4 -0
  11. data/app/assets/stylesheets/katalyst/tables/typed-columns/_index.scss +5 -0
  12. data/app/assets/stylesheets/katalyst/tables/typed-columns/_number.scss +5 -0
  13. data/app/components/concerns/katalyst/tables/body/typed_columns.rb +132 -0
  14. data/app/components/concerns/katalyst/tables/has_table_content.rb +1 -1
  15. data/app/components/concerns/katalyst/tables/header/typed_columns.rb +179 -0
  16. data/app/components/concerns/katalyst/tables/orderable.rb +1 -1
  17. data/app/components/concerns/katalyst/tables/selectable.rb +2 -1
  18. data/app/components/katalyst/table_component.rb +13 -1
  19. data/app/components/katalyst/tables/body/attachment_component.rb +58 -0
  20. data/app/components/katalyst/tables/body/boolean_component.rb +14 -0
  21. data/app/components/katalyst/tables/body/currency_component.rb +29 -0
  22. data/app/components/katalyst/tables/body/date_component.rb +64 -0
  23. data/app/components/katalyst/tables/body/date_time_component.rb +57 -0
  24. data/app/components/katalyst/tables/body/link_component.rb +40 -0
  25. data/app/components/katalyst/tables/body/number_component.rb +22 -0
  26. data/app/components/katalyst/tables/body/rich_text_component.rb +18 -0
  27. data/app/components/katalyst/tables/body_cell_component.rb +9 -1
  28. data/app/components/katalyst/tables/body_row_component.rb +9 -2
  29. data/app/components/katalyst/tables/empty_caption_component.rb +1 -1
  30. data/app/components/katalyst/tables/header/attachment_component.rb +15 -0
  31. data/app/components/katalyst/tables/header/boolean_component.rb +15 -0
  32. data/app/components/katalyst/tables/header/currency_component.rb +15 -0
  33. data/app/components/katalyst/tables/header/date_component.rb +15 -0
  34. data/app/components/katalyst/tables/header/date_time_component.rb +15 -0
  35. data/app/components/katalyst/tables/header/link_component.rb +15 -0
  36. data/app/components/katalyst/tables/header/number_component.rb +15 -0
  37. data/app/components/katalyst/tables/header/rich_text_component.rb +15 -0
  38. data/app/components/katalyst/tables/header_cell_component.rb +35 -3
  39. data/app/components/katalyst/tables/header_row_component.rb +3 -2
  40. data/app/components/katalyst/tables/selectable/form_component.html.erb +4 -2
  41. data/app/controllers/concerns/katalyst/tables/backend.rb +2 -2
  42. data/app/helpers/katalyst/tables/frontend.rb +2 -2
  43. data/app/models/concerns/katalyst/tables/collection/pagination.rb +8 -1
  44. data/app/models/concerns/katalyst/tables/collection/sorting.rb +3 -3
  45. data/app/models/katalyst/tables/collection/sort_form.rb +26 -8
  46. data/config/locales/tables.en.yml +6 -0
  47. metadata +33 -9
  48. data/app/components/concerns/katalyst/tables/turbo_replaceable.rb +0 -79
  49. data/app/components/katalyst/turbo/pagy_nav_component.rb +0 -23
  50. data/app/components/katalyst/turbo/table_component.rb +0 -45
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 10815e05f743cbe5d5c21845bf15e94318b2f0302c5466f55dc8094a34330fc9
4
- data.tar.gz: 0ded18dae608cee47f68ac143e55a63a58c7c36b5c2bfeb10add6ebd67771f32
3
+ metadata.gz: ac8dcee0526a034b23487868fb642c389e69c323aaf463a7aa6896bf777d5bc1
4
+ data.tar.gz: 8cea19cc8467137e533b9146daa65f51dacdf78763e4fde7904542261cbc66b3
5
5
  SHA512:
6
- metadata.gz: 4dc10673cee47c520e1b15f564f5ea532510d54923b97e13c5e49559fe2c474cb962b8955102182b2874889127012d74794efa99a9494aec1fedc0532ddea02a
7
- data.tar.gz: 2f65c7295d432fb3ada59eeb6d0c1dbc50aee134613ae922b583e738a5c7adc3fa83e1f3edc8833b96ae6642e6c88d0b492039cc0f30a72178997be211604d7f
6
+ metadata.gz: ea6efd6150d3bb2d9f9d48c89920831f97e6dede515cfcd99ec049f81328c32c373fbf49cfd798adde0f1d8055819e1eb4f40931f8ac392809006c384c219c98
7
+ data.tar.gz: 66480c79be3aa1762145c3d92723f284ed61749d46029600d20541820e2d831e266fa79ffa0de9ad77efc750ba80f274f7fee86267b7a946cad78ba8c49773da
data/CHANGELOG.md CHANGED
@@ -1,4 +1,9 @@
1
- ## [Unreleased]
1
+ ## [3.0.0.beta1]
2
+ - Breaking change: remove Turbo Streams from table and pagination components, focus preservation is handled via Turbo Morph
3
+ - Improve spec coverage
4
+ - Update examples in [README](README.md) and [docs](/docs) to reflect changes
5
+
6
+ ## [2.6.0]
2
7
 
3
8
  - Added table row selection
4
9
  - See [[docs/selectable.md]] for examples
data/README.md CHANGED
@@ -274,34 +274,12 @@ for a collection.
274
274
  <%= render Katalyst::Tables::PagyNavComponent.new(collection: @people) %>
275
275
  ```
276
276
 
277
- ## Turbo streams
278
-
279
- This gem provides turbo stream entry points for table and pagy_nav. These are
280
- identical in the options they support, but they require ids, and they will
281
- automatically render turbo stream replace tags when rendered as part of a turbo
282
- stream response.
283
-
284
- To take full advantage of this feature, we suggest you build the component in
285
- your controller and pass it to the view. This allows you to use the same
286
- controller for both HTML and turbo responses.
287
-
288
- ```ruby
289
- def index
290
- collection = ApplicationCollection.new.with_params(params).apply(People.all)
291
- table = Katalyst::Turbo::TableComponent.new(collection:, id: "people")
292
-
293
- respond_to do |format|
294
- format.turbo_stream { render table } if self_referred?
295
- format.html { render locals: { table: table } }
296
- end
297
- end
298
- ```
299
-
300
277
  ## Extensions
301
278
 
302
279
  The following extensions are available:
303
280
 
304
281
  * [Orderable](docs/orderable.md) - adds bulk-update for 'ordinal' columns via dragging rows in the table.
282
+ * [Selectable](docs/selectable.md) - adds bulk-action support for rows in the table.
305
283
 
306
284
  ## Customization
307
285
 
@@ -0,0 +1 @@
1
+ @use "table";
@@ -0,0 +1,38 @@
1
+ $width: 2rem !default;
2
+ $time: 125ms !default;
3
+
4
+ table {
5
+ tr {
6
+ transition:
7
+ top $time ease-in-out,
8
+ transform $time ease-in-out;
9
+ }
10
+
11
+ tr[dragging] {
12
+ transition: transform $time ease-in-out;
13
+ filter: drop-shadow(0 0 0.5rem var(--row-border-color));
14
+ transform: scale(1.01);
15
+ td {
16
+ box-shadow: none;
17
+ }
18
+ }
19
+
20
+ th.ordinal {
21
+ width: $width;
22
+ padding-left: 0;
23
+ a {
24
+ width: $width;
25
+ height: 3rem;
26
+ }
27
+ a::after {
28
+ right: 0;
29
+ }
30
+ }
31
+
32
+ td.ordinal {
33
+ width: $width;
34
+ padding-left: 0;
35
+ cursor: grab;
36
+ text-align: center;
37
+ }
38
+ }
@@ -0,0 +1,123 @@
1
+ @use "ordinal" as *;
2
+ @use "typed-columns";
3
+
4
+ $grey: #f0ecf3 !default;
5
+
6
+ $table-header-color: transparent !default;
7
+ $row-border-color: $grey !default;
8
+ $row-height: 48px !default;
9
+ $cell-spacing: 0.5rem !default;
10
+
11
+ $width-small: 6rem !default;
12
+ $width-medium: 12rem !default;
13
+ $width-large: 16rem !default;
14
+
15
+ table {
16
+ --row-height: #{$row-height};
17
+ --cell-spacing: #{$cell-spacing};
18
+ --table-header-color: #{$table-header-color};
19
+ --row-border-color: #{$row-border-color};
20
+
21
+ --width-small: #{$width-small};
22
+ --width-medium: #{$width-medium};
23
+ --width-large: #{$width-large};
24
+ }
25
+
26
+ table {
27
+ border: none;
28
+ table-layout: fixed;
29
+ border-collapse: collapse;
30
+ text-align: left;
31
+ width: 100%;
32
+
33
+ thead {
34
+ background: var(--table-header-color);
35
+ }
36
+
37
+ tr {
38
+ height: var(--row-height);
39
+ line-height: var(--row-height);
40
+ }
41
+
42
+ th,
43
+ td {
44
+ border: none;
45
+ box-shadow: inset 0px -1px 0px var(--row-border-color);
46
+ overflow: hidden;
47
+ text-overflow: ellipsis;
48
+ vertical-align: top;
49
+ white-space: nowrap;
50
+ background-color: white;
51
+ padding-right: var(--cell-spacing);
52
+
53
+ &:last-child {
54
+ padding-right: 0;
55
+ }
56
+
57
+ > a {
58
+ display: block;
59
+ overflow: hidden;
60
+ white-space: nowrap;
61
+ text-overflow: ellipsis;
62
+ text-decoration: none;
63
+ }
64
+
65
+ > img,
66
+ > a > img {
67
+ max-height: 3rem;
68
+ padding: 0;
69
+ }
70
+
71
+ > .trix-content {
72
+ overflow: hidden;
73
+ text-overflow: ellipsis;
74
+ }
75
+ }
76
+
77
+ th {
78
+ font-weight: bold;
79
+
80
+ :where(&.width-s) {
81
+ width: var(--width-small);
82
+ }
83
+
84
+ :where(&.width-m) {
85
+ width: var(--width-medium);
86
+ }
87
+
88
+ :where(&.width-l) {
89
+ width: var(--width-large);
90
+ }
91
+ }
92
+
93
+ thead a.ascending:after,
94
+ [data-sort="asc"] a::after {
95
+ display: inline-block;
96
+ content: " ";
97
+ position: relative;
98
+ margin-left: 1rem;
99
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 13'%3E%3Cpath d='M.541 0l11.125 12.573a.5.5 0 00.749 0L23.541 0h-23z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
100
+ background-size: 14px 14px;
101
+ height: 14px;
102
+ width: 14px;
103
+ top: 0;
104
+ transform: rotate(180deg);
105
+ }
106
+
107
+ thead a.descending:after,
108
+ [data-sort="desc"] a::after {
109
+ display: inline-block;
110
+ content: " ";
111
+ position: relative;
112
+ margin-left: 1rem;
113
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 13'%3E%3Cpath d='M.541 0l11.125 12.573a.5.5 0 00.749 0L23.541 0h-23z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
114
+ background-size: 14px 14px;
115
+ height: 14px;
116
+ width: 14px;
117
+ top: 4px;
118
+ }
119
+
120
+ caption {
121
+ margin: 2rem 0;
122
+ }
123
+ }
@@ -0,0 +1,4 @@
1
+ // where psuedo selector has a specificity of 0 so it can be easily overwritten with simple selectors
2
+ :where(th.type-boolean) {
3
+ width: var(--width-small);
4
+ }
@@ -0,0 +1,5 @@
1
+ // where psuedo selector has a specificity of 0 so it can be easily overwritten with simple selectors
2
+ :where(th.type-currency, td.type-currency) {
3
+ width: var(--width-small);
4
+ text-align: right;
5
+ }
@@ -0,0 +1,4 @@
1
+ // where psuedo selector has a specificity of 0 so it can be easily overwritten with simple selectors
2
+ :where(th.type-date) {
3
+ width: var(--width-medium);
4
+ }
@@ -0,0 +1,4 @@
1
+ // where psuedo selector has a specificity of 0 so it can be easily overwritten with simple selectors
2
+ :where(th.type-datetime) {
3
+ width: var(--width-medium);
4
+ }
@@ -0,0 +1,5 @@
1
+ @use "boolean";
2
+ @use "currency";
3
+ @use "date";
4
+ @use "datetime";
5
+ @use "number";
@@ -0,0 +1,5 @@
1
+ // where psuedo selector has a specificity of 0 so it can be easily overwritten with simple selectors
2
+ :where(th.type-number, td.type-number) {
3
+ width: var(--width-small);
4
+ text-align: right;
5
+ }
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Katalyst
4
+ module Tables
5
+ module Body
6
+ module TypedColumns
7
+ extend ActiveSupport::Concern
8
+
9
+ # Generates a column from boolean values rendered as "Yes" or "No".
10
+ #
11
+ # @param method [Symbol] the method to call on the record
12
+ # @param attributes [Hash] HTML attributes to be added to the cell
13
+ # @param block [Proc] optional block to alter the cell content
14
+ # @return [void]
15
+ #
16
+ # @example Render a boolean column indicating whether the record is active
17
+ # <% row.boolean :active %> # => <td>Yes</td>
18
+ def boolean(method, **attributes, &)
19
+ with_column(Body::BooleanComponent.new(@table, @record, method, **attributes), &)
20
+ end
21
+
22
+ # Generates a column from date values rendered using I18n.l.
23
+ # The default format is :admin, but it can be overridden.
24
+ #
25
+ # @param method [Symbol] the method to call on the record
26
+ # @param format [Symbol] the I18n date format to use when rendering
27
+ # @param attributes [Hash] HTML attributes to be added to the cell tag
28
+ # @param block [Proc] optional block to alter the cell content
29
+ # @return [void]
30
+ #
31
+ # @example Render a date column describing when the record was created
32
+ # <% row.date :created_at %> # => <td>29 Feb 2024</td>
33
+ def date(method, format: :table, **attributes, &)
34
+ with_column(Body::DateComponent.new(@table, @record, method, format:, **attributes), &)
35
+ end
36
+
37
+ # Generates a column from datetime values rendered using I18n.l.
38
+ # The default format is :admin, but it can be overridden.
39
+ #
40
+ # @param method [Symbol] the method to call on the record
41
+ # @param format [Symbol] the I18n datetime format to use when rendering
42
+ # @param attributes [Hash] HTML attributes to be added to the cell tag
43
+ # @param block [Proc] optional block to alter the cell content
44
+ # @return [void]
45
+ #
46
+ # @example Render a datetime column describing when the record was created
47
+ # <% row.datetime :created_at %> # => <td>29 Feb 2024, 5:00pm</td>
48
+ def datetime(method, format: :table, **attributes, &)
49
+ with_column(Body::DateTimeComponent.new(@table, @record, method, format:, **attributes), &)
50
+ end
51
+
52
+ # Generates a column from numeric values formatted appropriately.
53
+ #
54
+ # @param method [Symbol] the method to call on the record
55
+ # @param attributes [Hash] HTML attributes to be added to the cell tag
56
+ # @param block [Proc] optional block to alter the cell content
57
+ # @return [void]
58
+ #
59
+ # @example Render the number of comments on a post
60
+ # <% row.number :comment_count %> # => <td>0</td>
61
+ def number(method, **attributes, &)
62
+ with_column(Body::NumberComponent.new(@table, @record, method, **attributes), &)
63
+ end
64
+
65
+ # Generates a column from numeric values rendered using `number_to_currency`.
66
+ #
67
+ # @param method [Symbol] the method to call on the record
68
+ # @param options [Hash] options to be passed to `number_to_currency`
69
+ # @param attributes [Hash] HTML attributes to be added to the cell tag
70
+ # @param block [Proc] optional block to alter the cell content
71
+ # @return [void]
72
+ #
73
+ # @example Render a currency column for the price of a product
74
+ # <% row.currency :price %> # => <td>$3.50</td>
75
+ def currency(method, options: {}, **attributes, &)
76
+ with_column(Body::CurrencyComponent.new(@table, @record, method, options:, **attributes), &)
77
+ end
78
+
79
+ # Generates a column containing HTML markup.
80
+ #
81
+ # @param method [Symbol] the method to call on the record
82
+ # @param attributes [Hash] HTML attributes to be added to the cell tag
83
+ # @param block [Proc] optional block to alter the cell content
84
+ # @return [void]
85
+ #
86
+ # @note This method assumes that the method returns HTML-safe content.
87
+ # If the content is not HTML-safe, it will be escaped.
88
+ #
89
+ # @example Render a description column containing HTML markup
90
+ # <% row.rich_text :description %> # => <td><em>Emphasis</em></td>
91
+ def rich_text(method, **attributes, &)
92
+ with_column(Body::RichTextComponent.new(@table, @record, method, **attributes), &)
93
+ end
94
+
95
+ # Generates a column that links to the record's show page (by default).
96
+ #
97
+ # @param method [Symbol] the method to call on the record
98
+ # @param link [Hash] options to be passed to the link_to helper
99
+ # @option opts [Hash, Array, String, Symbol] :url ([:admin, object]) options for url_for,
100
+ # or a symbol to be passed to the route helper
101
+ # @param attributes [Hash] HTML attributes to be added to the cell tag
102
+ # @param block [Proc] optional block to alter the cell content
103
+ # @return [void]
104
+ #
105
+ # @example Render a column containing the record's title, linked to its show page
106
+ # <% row.link :title %> # => <td><a href="/admin/post/15">About us</a></td>
107
+ # @example Render a column containing the record's title, linked to its edit page
108
+ # <% row.link :title, url: :edit_admin_post_path do |cell| %>
109
+ # Edit <%= cell %>
110
+ # <% end %>
111
+ # # => <td><a href="/admin/post/15/edit">Edit About us</a></td>
112
+ def link(method, url: @record, link: {}, **attributes, &)
113
+ with_column(Body::LinkComponent.new(@table, @record, method, url:, link:, **attributes), &)
114
+ end
115
+
116
+ # Generates a column that renders an ActiveStorage attachment as a downloadable link.
117
+ #
118
+ # @param method [Symbol] the method to call on the record
119
+ # @param variant [Symbol] the variant to use when rendering the image (default :thumb)
120
+ # @param attributes [Hash] HTML attributes to be added to the cell tag
121
+ # @param block [Proc] optional block to alter the cell content
122
+ # @return [void]
123
+ #
124
+ # @example Render a column containing a download link to the record's background image
125
+ # <% row.attachment :background %> # => <td><a href="...">background.png</a></td>
126
+ def attachment(method, variant: :thumb, **attributes, &)
127
+ with_column(Body::AttachmentComponent.new(@table, @record, method, variant:, **attributes), &)
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -33,7 +33,7 @@ module Katalyst
33
33
 
34
34
  def row_renderer
35
35
  @row_renderer ||= RowRenderer.new(@lookup_context,
36
- collection: collection,
36
+ collection:,
37
37
  as: @as,
38
38
  partial: @partial,
39
39
  variants: [:row],
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Katalyst
4
+ module Tables
5
+ module Header
6
+ module TypedColumns
7
+ extend ActiveSupport::Concern
8
+
9
+ # Renders a boolean column header
10
+ # @param method [Symbol] the method to call on the record to get the value
11
+ # @param attributes [Hash] additional arguments are applied as html attributes to the th element
12
+ # @option attributes [String] :label (nil) The label options to display in the header
13
+ # @option attributes [Hash] :link ({}) The link options for the sorting link
14
+ # @option attributes [String] :width (nil) The width of the column, can be +:xs+, +:s+, +:m+, +:l+ or nil
15
+ #
16
+ # @example Render a boolean column header
17
+ # <% row.boolean :active %> # => <th>Active</th>
18
+ #
19
+ # @example Render a boolean column header with a custom label
20
+ # <% row.boolean :active, label: "Published" %> # => <th>Published</th>
21
+ #
22
+ # @example Render a boolean column header with small width
23
+ # <% row.boolean :active, width: :s %>
24
+ # => <th class="width-s">Active</th>
25
+ #
26
+ def boolean(method, **attributes, &)
27
+ with_column(Header::BooleanComponent.new(@table, method, link: @link_attributes, **attributes), &)
28
+ end
29
+
30
+ # Renders a date column header
31
+ # @param method [Symbol] the method to call on the record to get the value
32
+ # @param attributes [Hash] additional arguments are applied as html attributes to the th element
33
+ # @option attributes [String] :label (nil) The label options to display in the header
34
+ # @option attributes [Hash] :link ({}) The link options for the sorting link
35
+ # @option attributes [String] :width (nil) The width of the column, can be +:xs+, +:s+, +:m+, +:l+ or nil
36
+ #
37
+ # @example Render a date column header
38
+ # <% row.date :published_on %> # => <th>Published on</th>
39
+ #
40
+ # @example Render a date column header with a custom label
41
+ # <% row.date :published_on, label: "Date" %> # => <th>Date</th>
42
+ #
43
+ # @example Render a boolean column header with small width
44
+ # <% row.date :published_on, width: :s %>
45
+ # => <th class="width-s">Published on</th>
46
+ #
47
+ def date(method, **attributes, &)
48
+ with_column(Header::DateComponent.new(@table, method, link: @link_attributes, **attributes), &)
49
+ end
50
+
51
+ # Renders a datetime column header
52
+ # @param method [Symbol] the method to call on the record to get the value
53
+ # @param attributes [Hash] additional arguments are applied as html attributes to the th element
54
+ # @option attributes [String] :label (nil) The label options to display in the header
55
+ # @option attributes [Hash] :link ({}) The link options for the sorting link
56
+ # @option attributes [String] :width (nil) The width of the column, can be +:xs+, +:s+, +:m+, +:l+ or nil
57
+ #
58
+ # @example Render a datetime column header
59
+ # <% row.datetime :created_at %> # => <th>Created at</th>
60
+ #
61
+ # @example Render a datetime column header with a custom label
62
+ # <% row.datetime :created_at, label: "Published at" %> # => <th>Published at</th>
63
+ #
64
+ # @example Render a boolean column header with small width
65
+ # <% row.datetime :created_at, width: :s %>
66
+ # => <th class="width-s">Created at</th>
67
+ #
68
+ def datetime(method, **attributes, &)
69
+ with_column(Header::DateTimeComponent.new(@table, method, link: @link_attributes, **attributes), &)
70
+ end
71
+
72
+ # Renders a number column header
73
+ # @param method [Symbol] the method to call on the record to get the value
74
+ # @param attributes [Hash] additional arguments are applied as html attributes to the th element
75
+ # @option attributes [String] :label (nil) The label options to display in the header
76
+ # @option attributes [Hash] :link ({}) The link options for the sorting link
77
+ # @option attributes [String] :width (nil) The width of the column, can be +:xs+, +:s+, +:m+, +:l+ or nil
78
+ #
79
+ # @example Render a number column header
80
+ # <% row.number :comment_count %> # => <th>Comments</th>
81
+ #
82
+ # @example Render a number column header with a custom label
83
+ # <% row.number :comment_count, label: "Comments" %> # => <th>Comments</th>
84
+ #
85
+ # @example Render a boolean column header with small width
86
+ # <% row.number :comment_count, width: :s %>
87
+ # => <th class="width-s">Comments</th>
88
+ #
89
+ def number(method, **attributes, &)
90
+ with_column(Header::NumberComponent.new(@table, method, link: @link_attributes, **attributes), &)
91
+ end
92
+
93
+ # Renders a currency column header
94
+ # @param method [Symbol] the method to call on the record to get the value
95
+ # @param attributes [Hash] additional arguments are applied as html attributes to the th element
96
+ # @option attributes [String] :label (nil) The label options to display in the header
97
+ # @option attributes [Hash] :link ({}) The link options for the sorting link
98
+ # @option attributes [String] :width (nil) The width of the column, can be +:xs+, +:s+, +:m+, +:l+ or nil
99
+ #
100
+ # @example Render a currency column header
101
+ # <% row.currency :price %> # => <th>Price</th>
102
+ #
103
+ # @example Render a currency column header with a custom label
104
+ # <% row.currency :price, label: "Amount($)" %> # => <th>Amount($)</th>
105
+ #
106
+ # @example Render a boolean column header with small width
107
+ # <% row.currency :price, width: :s %>
108
+ # => <th class="width-s">Price</th>
109
+ #
110
+ def currency(method, **attributes, &)
111
+ with_column(Header::CurrencyComponent.new(@table, method, link: @link_attributes, **attributes), &)
112
+ end
113
+
114
+ # Renders a rich text column header
115
+ # @param method [Symbol] the method to call on the record to get the value
116
+ # @param attributes [Hash] additional arguments are applied as html attributes to the th element
117
+ # @option attributes [String] :label (nil) The label options to display in the header
118
+ # @option attributes [Hash] :link ({}) The link options for the sorting link
119
+ # @option attributes [String] :width (nil) The width of the column, can be +:xs+, +:s+, +:m+, +:l+ or nil
120
+ #
121
+ # @example Render a rich text header
122
+ # <% row.rich_text :content %> # => <th>Content</th>
123
+ #
124
+ # @example Render a rich text column header with a custom label
125
+ # <% row.currency :content, label: "Content!" %> # => <th>Content!</th>
126
+ #
127
+ # @example Render a boolean column header with small width
128
+ # <% row.currency :content, width: :s %>
129
+ # => <th class="width-s">Content</th>
130
+ #
131
+ def rich_text(method, **attributes, &)
132
+ with_column(Header::RichTextComponent.new(@table, method, link: @link_attributes, **attributes), &)
133
+ end
134
+
135
+ # Renders a link column header
136
+ # @param method [Symbol] the method to call on the record to get the value
137
+ # @param attributes [Hash] additional arguments are applied as html attributes to the th element
138
+ # @option attributes [String] :label (nil) The label options to display in the header
139
+ # @option attributes [Hash] :link ({}) The link options for the sorting link
140
+ # @option attributes [String] :width (nil) The width of the column, can be +:xs+, +:s+, +:m+, +:l+ or nil
141
+ #
142
+ # @example Render a link column header
143
+ # <% row.link :link %> # => <th>Link</th>
144
+ #
145
+ # @example Render a link column header with a custom label
146
+ # <% row.link :link, label: "Post" %> # => <th>Post</th>
147
+ #
148
+ # @example Render a boolean column header with small width
149
+ # <% row.link :link, width: :s %>
150
+ # => <th class="width-s">Link</th>
151
+ #
152
+ def link(method, **attributes, &)
153
+ with_column(Header::LinkComponent.new(@table, method, link: @link_attributes, **attributes), &)
154
+ end
155
+
156
+ # Renders a attachment column header
157
+ # @param method [Symbol] the method to call on the record to get the value
158
+ # @param attributes [Hash] additional arguments are applied as html attributes to the th element
159
+ # @option attributes [String] :label (nil) The label options to display in the header
160
+ # @option attributes [Hash] :link ({}) The link options for the sorting link
161
+ # @option attributes [String] :width (nil) The width of the column, can be +:xs+, +:s+, +:m+, +:l+ or nil
162
+ #
163
+ # @example Render a attachment column header
164
+ # <% row.attachment :attachment %> # => <th>Attachment</th>
165
+ #
166
+ # @example Render a attachment column header with a custom label
167
+ # <% row.attachment :attachment, label: "Document" %> # => <th>Document</th>
168
+ #
169
+ # @example Render a boolean column header with small width
170
+ # <% row.attachment :attachment, width: :s %>
171
+ # => <th class="width-s">Attachment</th>
172
+ #
173
+ def attachment(method, **attributes, &)
174
+ with_column(Header::AttachmentComponent.new(@table, method, link: @link_attributes, **attributes), &)
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
@@ -119,7 +119,7 @@ module Katalyst
119
119
  end
120
120
 
121
121
  def call
122
- form_with(id: id, url: url, method: :patch, data: { controller: FORM_CONTROLLER }) do |form|
122
+ form_with(id:, url:, method: :patch, data: { controller: FORM_CONTROLLER }) do |form|
123
123
  form.button(hidden: "")
124
124
  end
125
125
  end
@@ -73,7 +73,7 @@ module Katalyst
73
73
  def selection
74
74
  id = @record.public_send(@table.selection.primary_key)
75
75
  params = {
76
- id: id,
76
+ id:,
77
77
  }
78
78
  cell(:_selection,
79
79
  class: "selection",
@@ -82,6 +82,7 @@ module Katalyst
82
82
  "#{ITEM_CONTROLLER}-params-value" => params.to_json,
83
83
  "#{ITEM_CONTROLLER}-#{FORM_CONTROLLER}-outlet" => "##{@table.selection.id}",
84
84
  action: "change->#{ITEM_CONTROLLER}#change",
85
+ turbo_permanent: "",
85
86
  }) do
86
87
  tag.input(type: :checkbox)
87
88
  end
@@ -29,6 +29,7 @@ module Katalyst
29
29
  # - `sorting`: the sorting to apply to the collection (defaults to collection.storing if available)
30
30
  # - `header`: whether to render the header row (defaults to true, supports options)
31
31
  # - `caption`: whether to render the caption (defaults to true, supports options)
32
+ # - `generate_ids`: whether to generate ids for each row (defaults to true)
32
33
  # - `object_name`: the name of the object to use for partial rendering (defaults to collection.model_name.i18n_key)
33
34
  # - `partial`: the name of the partial to use for rendering each row (defaults to to_partial_path on the object)
34
35
  # - `as`: the name of the local variable to use for rendering each row (defaults to collection.model_name.param_key)
@@ -36,7 +37,8 @@ module Katalyst
36
37
  def initialize(collection:,
37
38
  sorting: nil,
38
39
  header: true,
39
- caption: false,
40
+ caption: true,
41
+ generate_ids: true,
40
42
  **html_attributes)
41
43
  @collection = collection
42
44
 
@@ -52,9 +54,15 @@ module Katalyst
52
54
  @caption = caption
53
55
  @caption_options = (caption if caption.is_a?(Hash)) || {}
54
56
 
57
+ @generate_ids = generate_ids
58
+
55
59
  super(**html_attributes)
56
60
  end
57
61
 
62
+ def id
63
+ html_attributes[:id]
64
+ end
65
+
58
66
  def caption?
59
67
  @caption.present?
60
68
  end
@@ -81,6 +89,10 @@ module Katalyst
81
89
  collection.sorting if collection.respond_to?(:sorting)
82
90
  end
83
91
 
92
+ def generate_ids?
93
+ @generate_ids.present?
94
+ end
95
+
84
96
  def inspect
85
97
  "#<#{self.class.name} collection: #{collection.inspect}>"
86
98
  end