katalyst-tables 2.6.0.beta → 3.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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