katalyst-tables 2.6.0 → 3.0.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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -1
  3. data/README.md +57 -213
  4. data/app/assets/builds/katalyst/tables.esm.js +17 -47
  5. data/app/assets/builds/katalyst/tables.js +17 -47
  6. data/app/assets/builds/katalyst/tables.min.js +1 -1
  7. data/app/assets/builds/katalyst/tables.min.js.map +1 -1
  8. data/app/assets/stylesheets/katalyst/tables/_index.scss +1 -0
  9. data/app/assets/stylesheets/katalyst/tables/_ordinal.scss +38 -0
  10. data/app/assets/stylesheets/katalyst/tables/_table.scss +123 -0
  11. data/app/assets/stylesheets/katalyst/tables/typed-columns/_boolean.scss +4 -0
  12. data/app/assets/stylesheets/katalyst/tables/typed-columns/_currency.scss +5 -0
  13. data/app/assets/stylesheets/katalyst/tables/typed-columns/_date.scss +4 -0
  14. data/app/assets/stylesheets/katalyst/tables/typed-columns/_datetime.scss +4 -0
  15. data/app/assets/stylesheets/katalyst/tables/typed-columns/_index.scss +5 -0
  16. data/app/assets/stylesheets/katalyst/tables/typed-columns/_number.scss +5 -0
  17. data/app/components/concerns/katalyst/tables/has_table_content.rb +17 -8
  18. data/app/components/concerns/katalyst/tables/identifiable.rb +51 -0
  19. data/app/components/concerns/katalyst/tables/orderable.rb +35 -105
  20. data/app/components/concerns/katalyst/tables/selectable.rb +18 -74
  21. data/app/components/concerns/katalyst/tables/sortable.rb +51 -17
  22. data/app/components/katalyst/table_component.html.erb +4 -4
  23. data/app/components/katalyst/table_component.rb +277 -47
  24. data/app/components/katalyst/tables/body_row_component.html.erb +5 -0
  25. data/app/components/katalyst/tables/body_row_component.rb +4 -24
  26. data/app/components/katalyst/tables/cell_component.rb +85 -0
  27. data/app/components/katalyst/tables/cells/boolean_component.rb +20 -0
  28. data/app/components/katalyst/tables/cells/currency_component.rb +29 -0
  29. data/app/components/katalyst/tables/cells/date_component.rb +67 -0
  30. data/app/components/katalyst/tables/cells/date_time_component.rb +60 -0
  31. data/app/components/katalyst/tables/cells/number_component.rb +22 -0
  32. data/app/components/katalyst/tables/cells/ordinal_component.rb +44 -0
  33. data/app/components/katalyst/tables/cells/rich_text_component.rb +21 -0
  34. data/app/components/katalyst/tables/cells/select_component.rb +39 -0
  35. data/app/components/katalyst/tables/data.rb +30 -0
  36. data/app/components/katalyst/tables/empty_caption_component.rb +1 -1
  37. data/app/components/katalyst/tables/header_row_component.html.erb +5 -0
  38. data/app/components/katalyst/tables/header_row_component.rb +4 -24
  39. data/app/components/katalyst/tables/label.rb +37 -0
  40. data/app/components/katalyst/tables/orderable/form_component.rb +38 -0
  41. data/app/components/katalyst/tables/selectable/form_component.html.erb +6 -4
  42. data/app/components/katalyst/tables/selectable/form_component.rb +8 -11
  43. data/app/controllers/concerns/katalyst/tables/backend.rb +2 -28
  44. data/app/helpers/katalyst/tables/frontend.rb +48 -2
  45. data/app/javascript/tables/application.js +0 -5
  46. data/app/javascript/tables/orderable/form_controller.js +8 -6
  47. data/app/javascript/tables/orderable/item_controller.js +9 -0
  48. data/app/models/concerns/katalyst/tables/collection/core.rb +6 -1
  49. data/app/models/concerns/katalyst/tables/collection/pagination.rb +8 -1
  50. data/app/models/concerns/katalyst/tables/collection/sorting.rb +85 -17
  51. data/app/models/katalyst/tables/collection/array.rb +38 -0
  52. data/app/models/katalyst/tables/collection/base.rb +4 -0
  53. data/lib/katalyst/tables/config.rb +23 -0
  54. data/lib/katalyst/tables.rb +9 -0
  55. metadata +32 -15
  56. data/app/components/concerns/katalyst/tables/configurable_component.rb +0 -52
  57. data/app/components/concerns/katalyst/tables/turbo_replaceable.rb +0 -79
  58. data/app/components/katalyst/tables/body_cell_component.rb +0 -47
  59. data/app/components/katalyst/tables/header_cell_component.rb +0 -65
  60. data/app/components/katalyst/turbo/pagy_nav_component.rb +0 -23
  61. data/app/components/katalyst/turbo/table_component.rb +0 -45
  62. data/app/helpers/katalyst/tables/frontend/helper.rb +0 -31
  63. data/app/javascript/tables/turbo/collection_controller.js +0 -38
  64. data/app/models/katalyst/tables/collection/sort_form.rb +0 -102
@@ -1,65 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Katalyst
4
- module Tables
5
- class HeaderCellComponent < ViewComponent::Base # :nodoc:
6
- include Frontend::Helper
7
- include Katalyst::HtmlAttributes
8
- include Sortable
9
-
10
- delegate :object_name, :collection, :sorting, to: :@table
11
-
12
- def initialize(table, attribute, label: nil, link: {}, **html_attributes)
13
- super(**html_attributes)
14
-
15
- @table = table
16
- @attribute = attribute
17
- @value = label
18
- @link_attributes = link
19
- end
20
-
21
- def call
22
- tag.th(**html_attributes) do
23
- if sortable?(@attribute)
24
- link_to(value, sort_url(@attribute), **@link_attributes)
25
- else
26
- value
27
- end
28
- end
29
- end
30
-
31
- def value
32
- if !@value.nil?
33
- @value
34
- elsif object_name.present?
35
- translation
36
- else
37
- default_value
38
- end
39
- end
40
-
41
- def translation(key = "activerecord.attributes.#{object_name}.#{@attribute}")
42
- translate(key, default: default_value)
43
- end
44
-
45
- def default_value
46
- @attribute.to_s.humanize.capitalize
47
- end
48
-
49
- def inspect
50
- "#<#{self.class.name} attribute: #{@attribute.inspect}, value: #{value.inspect}>"
51
- end
52
-
53
- # Backwards compatibility with tables 1.0
54
- alias_method :options, :html_attributes=
55
-
56
- private
57
-
58
- def default_html_attributes
59
- return {} unless sorting&.supports?(collection, @attribute)
60
-
61
- { data: { sort: sorting.status(@attribute) } }
62
- end
63
- end
64
- end
65
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Katalyst
4
- module Turbo
5
- class PagyNavComponent < Tables::PagyNavComponent # :nodoc:
6
- include Tables::TurboReplaceable
7
-
8
- def initialize(id:, **options)
9
- super(id:, **options)
10
- end
11
-
12
- def id
13
- pagy_options[:id]
14
- end
15
-
16
- private
17
-
18
- def pagy_options
19
- super.merge(anchor_string: "data-turbo-stream")
20
- end
21
- end
22
- end
23
- end
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Katalyst
4
- module Turbo
5
- # Renders a table that uses turbo stream replacement when sorting or
6
- # paginating.
7
- class TableComponent < ::Katalyst::TableComponent
8
- include Tables::TurboReplaceable
9
-
10
- attr_reader :id
11
-
12
- def initialize(collection:, id:, header: true, **options)
13
- header = if header.is_a?(Hash)
14
- default_header_options.merge(header)
15
- elsif header
16
- default_header_options
17
- end
18
-
19
- @id = id
20
-
21
- super(collection:, header:, id:, **options)
22
- end
23
-
24
- private
25
-
26
- def default_html_attributes
27
- {
28
- data: {
29
- controller: "tables--turbo--collection",
30
- tables__turbo__collection_query_value: current_query,
31
- tables__turbo__collection_sort_value: collection.sort,
32
- },
33
- }
34
- end
35
-
36
- def current_query
37
- Rack::Utils.build_nested_query(collection.to_params)
38
- end
39
-
40
- def default_header_options
41
- { link: { data: { turbo_stream: "" } } }
42
- end
43
- end
44
- end
45
- end
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Katalyst
4
- module Tables
5
- module Frontend
6
- # @deprecated Use {Katalyst::TableComponent} instead.
7
- module Helper # :nodoc:
8
- extend ActiveSupport::Concern
9
-
10
- # Generates a url for applying/toggling sort for the given column.
11
- #
12
- # @param sort [String, nil] sort parameter to apply, or nil to remove sorting
13
- # @return [String] URL for toggling column sorting
14
- # @deprecated Use {Katalyst::TablesComponent} instead.
15
- def sort_url_for(sort: nil, default: nil)
16
- # Implementation inspired by pagy's `pagy_url_for` helper.
17
- # Preserve any existing GET parameters
18
- # CAUTION: these parameters are not sanitised
19
- params = if sort && !sort.eql?(default)
20
- request.GET.merge("sort" => sort).except("page")
21
- else
22
- request.GET.except("page", "sort")
23
- end
24
- query_string = params.empty? ? "" : "?#{Rack::Utils.build_nested_query(params)}"
25
-
26
- "#{request.path}#{query_string}"
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,38 +0,0 @@
1
- import { Controller } from "@hotwired/stimulus";
2
- import { Turbo } from "@hotwired/turbo-rails";
3
-
4
- export default class TurboCollectionController extends Controller {
5
- static values = {
6
- query: String,
7
- sort: String,
8
- };
9
-
10
- queryValueChanged(query) {
11
- Turbo.navigator.history.replace(this.#url(query));
12
- }
13
-
14
- sortValueChanged(sort) {
15
- document.querySelectorAll(this.#sortSelector).forEach((input) => {
16
- if (input) input.value = sort;
17
- });
18
- }
19
-
20
- get #sortSelector() {
21
- return "input[name='sort']";
22
- }
23
-
24
- #url(query) {
25
- const frame = this.element.closest("turbo-frame");
26
- let url;
27
-
28
- if (frame) {
29
- url = new URL(frame.baseURI);
30
- } else {
31
- url = new URL(window.location.href);
32
- }
33
-
34
- url.search = query;
35
-
36
- return url;
37
- }
38
- }
@@ -1,102 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Katalyst
4
- module Tables
5
- module Collection
6
- # A FormObject (model) representing the sort state of controller for a given
7
- # collection/parameter.
8
- class SortForm
9
- DIRECTIONS = %w[asc desc].freeze
10
-
11
- attr_accessor :column, :direction, :default
12
-
13
- def self.parse(param, default: nil)
14
- column, direction = param.to_s.split
15
- direction = "asc" unless DIRECTIONS.include?(direction)
16
-
17
- default = SortForm.parse(default).to_param if default.present?
18
-
19
- SortForm.new(column:, direction:, default:)
20
- end
21
-
22
- def initialize(column: nil, direction: nil, default: nil)
23
- self.column = column
24
- self.direction = direction
25
- self.default = default
26
- end
27
-
28
- def to_param
29
- "#{column} #{direction}"
30
- end
31
-
32
- # Returns true if the given collection supports sorting on the given
33
- # column. A column supports sorting if it is a database column or if
34
- # the collection responds to `order_by_#{column}(direction)`.
35
- #
36
- # @param collection [ActiveRecord::Relation]
37
- # @param column [String, Symbol]
38
- # @return [true, false]
39
- def supports?(collection, column)
40
- scope_for(collection).respond_to?(:"order_by_#{column}") ||
41
- model_for(collection).has_attribute?(column.to_s)
42
- end
43
-
44
- # Returns the current sort behaviour of the given column, for use as a
45
- # column heading class in the table view.
46
- #
47
- # @param column [String, Symbol] the table column as defined in table_with
48
- # @return [String] the current sort behaviour of the given column
49
- def status(column)
50
- direction if column.to_s == self.column
51
- end
52
-
53
- # Calculates the sort parameter to apply when the given column is toggled.
54
- #
55
- # @param column [String, Symbol]
56
- # @return [String]
57
- def toggle(column)
58
- return "#{column} asc" unless column.to_s == self.column
59
-
60
- case direction
61
- when "asc"
62
- "#{column} desc"
63
- when "desc"
64
- "#{column} asc"
65
- end
66
- end
67
-
68
- # Apply the constructed sort ordering to the collection.
69
- #
70
- # @param collection [ActiveRecord::Relation]
71
- # @return [Array(SortForm, ActiveRecord::Relation)]
72
- def apply(collection)
73
- return [self, collection] if column.nil?
74
-
75
- if collection.respond_to?(:"order_by_#{column}")
76
- collection = collection.reorder(nil).public_send(:"order_by_#{column}", direction.to_sym)
77
- elsif collection.model.has_attribute?(column)
78
- collection = collection.reorder(column => direction)
79
- else
80
- clear!
81
- end
82
-
83
- [self, collection]
84
- end
85
-
86
- private
87
-
88
- def clear!
89
- self.column = self.direction = nil
90
- end
91
-
92
- def scope_for(collection)
93
- collection.is_a?(Core) ? collection.items : collection
94
- end
95
-
96
- def model_for(collection)
97
- scope_for(collection).model
98
- end
99
- end
100
- end
101
- end
102
- end