phlexi-table 0.0.2 → 0.0.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a2fc89d8ce811c592ca3a145af7ce3c91171d767404ec497a117a609e26c2f6a
4
- data.tar.gz: 72d3289f57300d9f05a717cc9745d223971c0c143a9245e6e8a54c0ed5b6303c
3
+ metadata.gz: ea441f5dc6bff0752e14011507ba3274026a46f8900de536f7b1d253fff45c44
4
+ data.tar.gz: 05dd06af33197b2f8847d2bfab878340cf23d28d9c824b53382497343ae1de13
5
5
  SHA512:
6
- metadata.gz: 5aab0ea7be94c1f55a554b10b21710d2e4c6dd98ad0f9e1e1671660a03327e569163acaad34ae6ba1f57f7f5f0759ff58d73e553d366f64d939e4ecea9b53bed
7
- data.tar.gz: 8132fba9adc5135022108759ff28ba5cd568ee818e307ce5fc0f36c11f19715b170af523fb4c90856ee718f2c29415fba8b7a281dc4125e365042f9ce54972fa
6
+ metadata.gz: 5db97df1ef5cf3131212ee6ce6a9b043dffd5d97f68e783ceca071b95cbedbb3a7a57086d82d0285cd100714e6aa0994001615f99768a56154cd4296df2eac75
7
+ data.tar.gz: 48935e08c5e0dfb4b9fb110ebe7a14cffc5d3a73930a0ad7779e89fbe3579c4a19ebe72062deaac07df84b8a47fe73351ee7a0e8555bdadf79c01e02ba72d9df
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "phlex"
4
- # require "phlexi-display"
5
-
6
3
  module Phlexi
7
4
  module Table
8
5
  # Base class for creating customizable table components
@@ -31,15 +28,19 @@ module Phlexi
31
28
  # @attr_reader [Hash] columns The columns defined for the table
32
29
  class Base < Phlexi::Table::HTML
33
30
  include Phlex::DeferredRender
34
- include Phlexi::Table::TableOptions::Captions
35
- include Phlexi::Table::TableOptions::Descriptions
31
+ include Phlexi::Table::Options::Captions
32
+ include Phlexi::Table::Options::Descriptions
36
33
 
37
- class Column < Phlexi::Table::Components::Column; end
34
+ class DataColumn < Phlexi::Table::Components::DataColumn; end
38
35
 
39
- class ColumnGroup < Phlexi::Table::Components::ColumnGroup; end
36
+ class SelectionColumn < Phlexi::Table::Components::SelectionColumn; end
40
37
 
41
38
  class ActionsColumn < Phlexi::Table::Components::ActionsColumn; end
42
39
 
40
+ class ColumnGroup < Phlexi::Table::Components::ColumnGroup; end
41
+
42
+ class Display < Phlexi::Display::Base; end
43
+
43
44
  attr_reader :key, :collection, :columns, :options
44
45
 
45
46
  # Initialize a new table component
@@ -50,35 +51,55 @@ module Phlexi
50
51
  # @option options [String] :class The CSS class(es) for the table
51
52
  # @raise [ArgumentError] If the collection is empty
52
53
  def initialize(collection, **options)
53
- raise ArgumentError, "Collection cannot be empty" if collection.empty?
54
+ @collection = Array(collection)
55
+ raise ArgumentError, "Collection cannot be empty" if @collection.empty?
54
56
 
55
- @collection = collection
56
57
  @columns = {}
57
58
  @options = options
58
59
  initialize_key
59
60
  end
60
61
 
62
+ def around_template
63
+ original_template = Phlexi::Display::Theme.instance
64
+ Phlexi::Display::Theme.instance = Phlexi::Table::DisplayTheme.instance
65
+ super
66
+ ensure
67
+ Phlexi::Display::Theme.instance = original_template
68
+ end
69
+
70
+ def before_template
71
+ super
72
+ table_template
73
+ end
74
+
61
75
  def view_template
62
76
  render_table
63
77
  end
64
78
 
65
79
  def table_template
80
+ # implement this in subclasses to define the column template
66
81
  end
67
82
 
68
- def column(key, **options, &)
69
- if options[:as] == :selection
70
- selection_column(key, self, **options, &)
71
- else
83
+ # Add a column to the table
84
+ #
85
+ # @param column [Columns::Base] The column object to add
86
+ # @return [void]
87
+ # @raise [ArgumentError] If a column with the same key already exists
88
+ def add_column(column)
89
+ raise ArgumentError, "Column '#{column.key}' already exists" if @columns.key?(column.key)
90
+
91
+ @columns[column.key] = column
92
+ end
72
93
 
73
- add_column(column_class.new(key, self, **options, &))
74
- end
94
+ def column(key, **, &)
95
+ add_column(column_class.new(key, self, **, &))
75
96
  end
76
97
 
77
98
  def selection_column(key, **, &)
78
99
  raise "Selection column already added" if @has_selection_column
79
100
 
80
101
  @has_selection_column = true
81
- add_column(column_class.new(key, self, **, as: :selection, &))
102
+ add_column(selection_column_class.new(key, self, **, &))
82
103
  end
83
104
 
84
105
  def column_group(key, **, &)
@@ -97,29 +118,32 @@ module Phlexi
97
118
  collection[0]
98
119
  end
99
120
 
121
+ def wrapped_sample
122
+ @wrapped_sample ||= WrappedObject.new(sample, index: -1, display_class: self.class::Display)
123
+ end
124
+
100
125
  def dom_id
101
126
  key
102
127
  end
103
128
 
104
129
  def column_class
105
- self.class::Column
130
+ self.class::DataColumn
106
131
  end
107
132
 
108
- def column_group_class
109
- self.class::ColumnGroup
133
+ def selection_column_class
134
+ self.class::SelectionColumn
110
135
  end
111
136
 
112
137
  def actions_column_class
113
138
  self.class::ActionsColumn
114
139
  end
115
140
 
116
- protected
117
-
118
- def before_template
119
- super
120
- table_template
141
+ def column_group_class
142
+ self.class::ColumnGroup
121
143
  end
122
144
 
145
+ protected
146
+
123
147
  # Render the complete table structure
124
148
  #
125
149
  # @return [void]
@@ -190,28 +214,28 @@ module Phlexi
190
214
  # @return [void]
191
215
  def render_table_body
192
216
  tbody(**table_body_attributes) do
193
- collection.each_with_index do |item, index|
194
- object = WrappedObject.new(item, index:)
195
- render_table_body_row(object)
217
+ collection.each_with_index do |object, index|
218
+ wrapped_object = WrappedObject.new(object, index:, display_class: self.class::Display)
219
+ render_table_body_row(wrapped_object)
196
220
  end
197
221
  end
198
222
  end
199
223
 
200
224
  # Render a table body row
201
225
  #
202
- # @param item [Object] The current item from the collection
226
+ # @param wrapped_object [Object] The current item from the collection
203
227
  # @return [void]
204
- def render_table_body_row(object)
205
- tr(**table_body_row_attributes(object)) do
228
+ def render_table_body_row(wrapped_object)
229
+ tr(**table_body_row_attributes(wrapped_object)) do
206
230
  columns.each_value do |column|
207
231
  if column.is_a?(Phlexi::Table::Components::Concerns::GroupsColumns)
208
232
  column.columns.each_value do |column|
209
- td(**table_data_cell_attributes(object, column)) { render column.data_cell(object) }
233
+ td(**table_data_cell_attributes(wrapped_object, column)) { render column.data_cell(wrapped_object) }
210
234
  end
211
235
  elsif column.is_a?(actions_column_class)
212
- td(**table_data_cell_attributes(object, column)) { column.render_actions(object.unwrapped) }
236
+ td(**table_data_cell_attributes(wrapped_object, column)) { column.render_actions(wrapped_object) }
213
237
  else
214
- td(**table_data_cell_attributes(object, column)) { render column.data_cell(object) }
238
+ td(**table_data_cell_attributes(wrapped_object, column)) { render column.data_cell(wrapped_object) }
215
239
  end
216
240
  end
217
241
  end
@@ -325,27 +349,27 @@ module Phlexi
325
349
 
326
350
  # Get the attributes for a table body row element
327
351
  #
328
- # @param item [Object] The current item from the collection
352
+ # @param wrapped_object [Object] The current item from the collection
329
353
  # @return [Hash] The body row attributes
330
- def table_body_row_attributes(item)
354
+ def table_body_row_attributes(wrapped_object)
331
355
  {
332
- id: "#{dom_id}_table_row_#{item.id}",
356
+ id: "#{dom_id}_table_row_#{wrapped_object.identifier}",
333
357
  class: tokens("phlexi_table_body_row", themed(:body_row))
334
358
  }
335
359
  end
336
360
 
337
361
  # Get the attributes for a table body cell element
338
362
  #
339
- # @param item [Object] The current item from the collection
363
+ # @param wrapped_object [Object] The current item from the collection
340
364
  # @param column [Columns::Base] The column object
341
365
  # @return [Hash] The body cell attributes
342
- def table_data_cell_attributes(item, column)
366
+ def table_data_cell_attributes(wrapped_object, column)
343
367
  mix(
344
368
  {
345
- id: "#{dom_id}_table_row_#{item.id}_#{column.key}",
369
+ id: "#{dom_id}_table_row_#{wrapped_object.identifier}_#{column.key}",
346
370
  class: tokens("phlexi_table_data_cell", themed(:body_cell))
347
371
  },
348
- column.data_cell_attributes(item)
372
+ column.data_cell_attributes(wrapped_object)
349
373
  )
350
374
  end
351
375
 
@@ -359,17 +383,6 @@ module Phlexi
359
383
  }
360
384
  end
361
385
 
362
- # Add a column to the table
363
- #
364
- # @param column [Columns::Base] The column object to add
365
- # @return [void]
366
- # @raise [ArgumentError] If a column with the same key already exists
367
- def add_column(column)
368
- raise ArgumentError, "Column '#{column.key}' already exists" if @columns.key?(column.key)
369
-
370
- @columns[column.key] = column
371
- end
372
-
373
386
  def initialize_key
374
387
  # always pop these keys
375
388
  # add support for `as` to make it more rails friendly
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "phlex"
4
-
5
3
  module Phlexi
6
4
  module Table
7
5
  module Components
@@ -33,11 +31,7 @@ module Phlexi
33
31
  end
34
32
 
35
33
  def data_cell_attributes(object)
36
- attributes = @attributes.dup
37
- attributes[:class] = tokens(
38
- themed(:actions_row_cell)
39
- )
40
- attributes
34
+ @attributes
41
35
  end
42
36
 
43
37
  def type = "actions"
@@ -1,16 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "phlex"
4
-
5
3
  module Phlexi
6
4
  module Table
7
5
  module Components
8
6
  class Base
9
7
  include Phlex::Helpers
8
+ include Phlexi::Table::HTML::Behaviour
10
9
 
11
10
  attr_reader :key, :parent, :options
12
11
 
13
- delegate :sample, to: :parent
12
+ delegate :sample, :wrapped_sample, to: :parent
14
13
 
15
14
  def initialize(key, parent, **options)
16
15
  @key = key
@@ -34,8 +33,8 @@ module Phlexi
34
33
  }
35
34
  end
36
35
 
37
- def themed(component)
38
- Phlexi::Table::Theme.instance.resolve_theme(component)
36
+ def type
37
+ options[:as] || wrapped_sample.field(key).inferred_field_type
39
38
  end
40
39
  end
41
40
  end
@@ -1,23 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "phlex"
4
-
5
3
  module Phlexi
6
4
  module Table
7
5
  module Components
8
6
  class Column < Base
9
- include Phlexi::Table::Components::Options::Types
10
7
  include Phlexi::Table::Components::Options::Labels
11
8
  include Phlexi::Table::Components::Options::Alignment
12
- include Phlexi::Table::Components::Options::Attachments
13
- include Phlexi::Table::Components::Options::Associations
14
9
  include Phlexi::Table::Components::Concerns::DisplaysHeader
15
10
  include Phlexi::Table::Components::Concerns::DisplaysData
16
-
17
- def initialize(*, **, &block)
18
- super(*, **)
19
- @block = block
20
- end
21
11
  end
22
12
  end
23
13
  end
@@ -7,41 +7,12 @@ module Phlexi
7
7
  module DisplaysData
8
8
  extend ActiveSupport::Concern
9
9
 
10
- class DataCell < Phlexi::Table::HTML
11
- def initialize(value)
12
- @value = value
13
- end
14
-
15
- def view_template
16
- plain @value.to_s
17
- end
18
- end
19
-
20
- class SelectionCell < Phlexi::Table::HTML
21
- def initialize(value)
22
- @value = value
23
- end
24
-
25
- def view_template
26
- input(type: :checkbox, value: @value, class: themed(:selection_checkbox))
27
- end
28
- end
29
-
30
- def data_cell(object)
31
- case type
32
- when :selection
33
- selection_cell_class.new(object.value_of(key))
34
- else
35
- data_cell_class.new(object.value_of(key))
36
- end
10
+ def data_cell(wrapped_object)
11
+ raise NotImplementedError, "#{self.class} must implement #data_cell"
37
12
  end
38
13
 
39
- def data_cell_attributes(object)
14
+ def data_cell_attributes(wrapped_object)
40
15
  attributes = @attributes.dup
41
- case type
42
- when :name, :selection
43
- attributes["scope"] = "row"
44
- end
45
16
  attributes[:class] = tokens(
46
17
  attributes[:class],
47
18
  themed(:"align_#{alignment}"),
@@ -49,16 +20,6 @@ module Phlexi
49
20
  )
50
21
  attributes
51
22
  end
52
-
53
- private
54
-
55
- def selection_cell_class
56
- self.class::SelectionCell
57
- end
58
-
59
- def data_cell_class
60
- self.class::DataCell
61
- end
62
23
  end
63
24
  end
64
25
  end
@@ -7,80 +7,8 @@ module Phlexi
7
7
  module DisplaysHeader
8
8
  extend ActiveSupport::Concern
9
9
 
10
- class HeaderCell < Phlexi::Table::HTML
11
- def initialize(value, sort_params:)
12
- @value = value
13
- @sort_params = sort_params
14
- end
15
-
16
- def view_template
17
- div(class: "flex items-center") do
18
- if !@sort_params
19
- plain @value.to_s
20
- next
21
- end
22
-
23
- a(class: "flex items-center", href: @sort_params[:url]) do
24
- plain @value.to_s
25
-
26
- sort_icon = Phlexi::Table::Theme.instance.resolve_theme(:sort_icon)
27
- sort_icon_active = Phlexi::Table::Theme.instance.resolve_theme(:sort_icon_active)
28
-
29
- span(class: "ml-1.5") {
30
- svg(
31
- class: tokens(sort_icon, -> { @sort_params[:direction] != "DESC" } => sort_icon_active),
32
- aria_hidden: "true",
33
- xmlns: "http://www.w3.org/2000/svg",
34
- fill: "none",
35
- viewbox: "0 0 10 6"
36
- ) do |s|
37
- s.path(
38
- stroke: "currentColor",
39
- stroke_linecap: "round",
40
- stroke_linejoin: "round",
41
- stroke_width: "2",
42
- d: "M9 5 5 1 1 5"
43
- )
44
- end
45
- svg(
46
- class: tokens(sort_icon, -> { @sort_params[:direction] != "ASC" } => sort_icon_active),
47
- aria_hidden: "true",
48
- xmlns: "http://www.w3.org/2000/svg",
49
- fill: "none",
50
- viewbox: "0 0 10 6"
51
- ) do |s|
52
- s.path(
53
- stroke: "currentColor",
54
- stroke_linecap: "round",
55
- stroke_linejoin: "round",
56
- stroke_width: "2",
57
- d: "M1 1 5 5 9 1"
58
- )
59
- end
60
- }
61
- end
62
-
63
- next if @sort_params[:position].nil?
64
-
65
- sort_index_clear_link = Phlexi::Table::Theme.instance.resolve_theme(:sort_index_clear_link)
66
- sort_index_clear_link_text = Phlexi::Table::Theme.instance.resolve_theme(:sort_index_clear_link_text)
67
- sort_index_clear_link_icon = Phlexi::Table::Theme.instance.resolve_theme(:sort_index_clear_link_icon)
68
-
69
- a(href: @sort_params[:reset_url], title: "Clear sort", class: sort_index_clear_link) {
70
- span(class: sort_index_clear_link_text) { (@sort_params[:position] + 1).to_s }
71
- span(class: sort_index_clear_link_icon) { "✕" }
72
- }
73
- end
74
- end
75
- end
76
-
77
10
  def header_cell
78
- case type
79
- when :selection
80
- selection_cell_class.new(nil)
81
- else
82
- header_cell_class.new(label, sort_params:)
83
- end
11
+ HeaderCell.new(label)
84
12
  end
85
13
 
86
14
  def header_cell_attributes
@@ -95,18 +23,6 @@ module Phlexi
95
23
  end
96
24
 
97
25
  def colspan = 1
98
-
99
- protected
100
-
101
- def sort_params
102
- options[:sort_params]
103
- end
104
-
105
- private
106
-
107
- def header_cell_class
108
- self.class::HeaderCell
109
- end
110
26
  end
111
27
  end
112
28
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Table
5
+ module Components
6
+ class DataColumn < Column
7
+ def initialize(*, **, &block)
8
+ super(*, **)
9
+ @block = block
10
+ end
11
+
12
+ def header_cell
13
+ SortableHeaderCell.new(label, sort_params:)
14
+ end
15
+
16
+ def data_cell(wrapped_object)
17
+ if @block
18
+ @block.call(wrapped_object, key)
19
+ else
20
+ field = wrapped_object.field(key)
21
+ field.send(:"#{field.inferred_field_component}_tag")
22
+ end
23
+ end
24
+
25
+ protected
26
+
27
+ def sort_params
28
+ options[:sort_params]
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Table
5
+ module Components
6
+ class HeaderCell < Phlexi::Table::HTML
7
+ def initialize(value)
8
+ @value = value
9
+ end
10
+
11
+ def view_template
12
+ div(class: themed(:header_cell_content_wrapper)) do
13
+ plain @value.to_s
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -7,9 +7,9 @@ module Phlexi
7
7
  module Alignment
8
8
  def alignment(alignment = nil)
9
9
  if alignment.nil?
10
- options[:alignment] = options.fetch(:alignment) { calculate_alignment }
10
+ options[:align] = options.fetch(:align) { calculate_alignment }
11
11
  else
12
- options[:alignment] = alignment
12
+ options[:align] = alignment
13
13
  self
14
14
  end
15
15
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Table
5
+ module Components
6
+ class SelectionCell < Phlexi::Table::HTML
7
+ def initialize(value)
8
+ @value = value
9
+ end
10
+
11
+ def view_template
12
+ input(type: :checkbox, value: @value, class: themed(:selection_checkbox))
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Table
5
+ module Components
6
+ class SelectionColumn < Column
7
+ def header_cell
8
+ SelectionCell.new("all")
9
+ end
10
+
11
+ def data_cell(wrapped_object)
12
+ SelectionCell.new(wrapped_object.field(key).dom.value)
13
+ end
14
+
15
+ def data_cell_attributes(wrapped_object)
16
+ {scope: :row}.merge(super)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Table
5
+ module Components
6
+ class SortableHeaderCell < HeaderCell
7
+ def initialize(value, sort_params:)
8
+ @value = value
9
+ @sort_params = sort_params
10
+ end
11
+
12
+ def view_template
13
+ div(class: themed(:header_cell_content_wrapper)) do
14
+ if !@sort_params
15
+ plain @value.to_s
16
+ next
17
+ end
18
+
19
+ a(class: themed(:header_cell_sort_wrapper), href: @sort_params[:url]) do
20
+ plain @value.to_s
21
+
22
+ sort_icon = themed(:sort_icon)
23
+ sort_icon_active = themed(:sort_icon_active)
24
+
25
+ span(class: themed(:header_cell_sort_indicator)) {
26
+ svg(
27
+ class: tokens(sort_icon, -> { @sort_params[:direction] != "DESC" } => sort_icon_active),
28
+ aria_hidden: "true",
29
+ xmlns: "http://www.w3.org/2000/svg",
30
+ fill: "none",
31
+ viewbox: "0 0 10 6"
32
+ ) do |s|
33
+ s.path(
34
+ stroke: "currentColor",
35
+ stroke_linecap: "round",
36
+ stroke_linejoin: "round",
37
+ stroke_width: "2",
38
+ d: "M9 5 5 1 1 5"
39
+ )
40
+ end
41
+ svg(
42
+ class: tokens(sort_icon, -> { @sort_params[:direction] != "ASC" } => sort_icon_active),
43
+ aria_hidden: "true",
44
+ xmlns: "http://www.w3.org/2000/svg",
45
+ fill: "none",
46
+ viewbox: "0 0 10 6"
47
+ ) do |s|
48
+ s.path(
49
+ stroke: "currentColor",
50
+ stroke_linecap: "round",
51
+ stroke_linejoin: "round",
52
+ stroke_width: "2",
53
+ d: "M1 1 5 5 9 1"
54
+ )
55
+ end
56
+ }
57
+ end
58
+
59
+ next if @sort_params[:position].nil?
60
+
61
+ sort_index_clear_link = themed(:sort_index_clear_link)
62
+ sort_index_clear_link_text = themed(:sort_index_clear_link_text)
63
+ sort_index_clear_link_icon = themed(:sort_index_clear_link_icon)
64
+
65
+ a(href: @sort_params[:reset_url], title: "Clear sort", class: sort_index_clear_link) {
66
+ span(class: sort_index_clear_link_text) { (@sort_params[:position] + 1).to_s }
67
+ span(class: sort_index_clear_link_icon) { "✕" }
68
+ }
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,6 @@
1
+ module Phlexi
2
+ module Table
3
+ class DisplayTheme < Phlexi::Display::Theme
4
+ end
5
+ end
6
+ end
@@ -1,13 +1,15 @@
1
- require "phlex"
2
-
3
1
  module Phlexi
4
2
  module Table
5
3
  class HTML < (defined?(::ApplicationComponent) ? ::ApplicationComponent : Phlex::HTML)
6
- protected
4
+ module Behaviour
5
+ protected
7
6
 
8
- def themed(component)
9
- Phlexi::Table::Theme.instance.resolve_theme(component)
7
+ def themed(component)
8
+ Phlexi::Table::Theme.instance.resolve_theme(component)
9
+ end
10
10
  end
11
+
12
+ include Behaviour
11
13
  end
12
14
  end
13
15
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Phlexi
4
4
  module Table
5
- module TableOptions
5
+ module Options
6
6
  module Captions
7
7
  def table_caption(caption = nil)
8
8
  if caption.nil?
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Phlexi
4
4
  module Table
5
- module TableOptions
5
+ module Options
6
6
  module Descriptions
7
7
  def table_description(description = nil)
8
8
  if description.nil?
@@ -1,28 +1,24 @@
1
1
  module Phlexi
2
2
  module Table
3
- class Theme
4
- include Phlexi::Field::Theme
5
-
6
- DEFAULT_THEME = {
7
- wrapper: nil,
8
- base: nil,
9
- caption: nil,
10
- description: nil,
11
- header: nil,
12
- header_grouping_row: :header_row,
13
- header_grouping_cell: :header_row_cell,
14
- header_row: nil,
15
- header_cell: nil,
16
- body_row: nil,
17
- body_cell: nil,
18
- name_column: nil,
19
- align_end: nil,
20
- selection_checkbox: nil,
21
- actions_row_cell: nil
22
- }.freeze
23
-
24
- def theme
25
- DEFAULT_THEME
3
+ class Theme < Phlexi::Field::Theme
4
+ def self.theme
5
+ {
6
+ wrapper: nil,
7
+ base: nil,
8
+ caption: nil,
9
+ description: nil,
10
+ header: nil,
11
+ header_grouping_row: :header_row,
12
+ header_grouping_cell: :header_row_cell,
13
+ header_row: nil,
14
+ header_cell: nil,
15
+ body_row: nil,
16
+ body_cell: nil,
17
+ name_column: nil,
18
+ align_start: nil,
19
+ align_end: nil,
20
+ selection_checkbox: nil
21
+ }.freeze
26
22
  end
27
23
  end
28
24
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Phlexi
4
4
  module Table
5
- VERSION = "0.0.2"
5
+ VERSION = "0.0.3"
6
6
  end
7
7
  end
@@ -1,20 +1,27 @@
1
1
  module Phlexi
2
2
  module Table
3
3
  class WrappedObject
4
- attr_reader :unwrapped
4
+ attr_reader :unwrapped, :index
5
5
 
6
- def initialize(object, index:)
6
+ delegate :field, to: :as_display
7
+
8
+ def initialize(object, index:, display_class:)
7
9
  @unwrapped = object
8
10
  @index = index
11
+ @display_class = display_class
9
12
  end
10
13
 
11
- def id
12
- value_of(:id) || index
14
+ def identifier
15
+ @identifier ||= Phlexi::Field.object_primary_key(unwrapped) || (index + 1)
13
16
  end
14
17
 
15
18
  def value_of(key)
16
19
  @unwrapped.try(key)
17
20
  end
21
+
22
+ def as_display
23
+ @as_display ||= @display_class.new(unwrapped)
24
+ end
18
25
  end
19
26
  end
20
27
  end
data/lib/phlexi/table.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "zeitwerk"
4
+ require "phlex"
5
+ require "phlexi-field"
6
+ require "phlexi-display"
4
7
  require "active_support/core_ext/object/blank"
5
8
 
6
9
  module Phlexi
@@ -17,8 +20,6 @@ module Phlexi
17
20
  loader.setup
18
21
  end
19
22
 
20
- NIL_VALUE = :__i_phlexi_display_nil_value_i__
21
-
22
23
  class Error < StandardError; end
23
24
  end
24
25
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: phlexi-table
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stefan Froelich
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-09-08 00:00:00.000000000 Z
11
+ date: 2024-09-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: phlex
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: phlexi-display
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rake
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -206,14 +220,17 @@ files:
206
220
  - lib/phlexi/table/components/concerns/displays_data.rb
207
221
  - lib/phlexi/table/components/concerns/displays_header.rb
208
222
  - lib/phlexi/table/components/concerns/groups_columns.rb
223
+ - lib/phlexi/table/components/data_column.rb
224
+ - lib/phlexi/table/components/header_cell.rb
209
225
  - lib/phlexi/table/components/options/alignment.rb
210
- - lib/phlexi/table/components/options/associations.rb
211
- - lib/phlexi/table/components/options/attachments.rb
212
226
  - lib/phlexi/table/components/options/labels.rb
213
- - lib/phlexi/table/components/options/types.rb
227
+ - lib/phlexi/table/components/selection_cell.rb
228
+ - lib/phlexi/table/components/selection_column.rb
229
+ - lib/phlexi/table/components/sortable_header_cell.rb
230
+ - lib/phlexi/table/display_theme.rb
214
231
  - lib/phlexi/table/html.rb
215
- - lib/phlexi/table/table_options/captions.rb
216
- - lib/phlexi/table/table_options/descriptions.rb
232
+ - lib/phlexi/table/options/captions.rb
233
+ - lib/phlexi/table/options/descriptions.rb
217
234
  - lib/phlexi/table/theme.rb
218
235
  - lib/phlexi/table/version.rb
219
236
  - lib/phlexi/table/wrapped_object.rb
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phlexi
4
- module Table
5
- module Components
6
- module Options
7
- module Associations
8
- protected
9
-
10
- def association_reflection
11
- @association_reflection ||= find_association_reflection
12
- end
13
-
14
- def find_association_reflection
15
- if sample.class.respond_to?(:reflect_on_association)
16
- sample.class.reflect_on_association(key)
17
- end
18
- end
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phlexi
4
- module Table
5
- module Components
6
- module Options
7
- module Attachments
8
- protected
9
-
10
- def attachment_reflection
11
- @attachment_reflection ||= find_attachment_reflection
12
- end
13
-
14
- def find_attachment_reflection
15
- if sample.class.respond_to?(:reflect_on_attachment)
16
- sample.class.reflect_on_attachment(key)
17
- end
18
- end
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,140 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "bigdecimal"
4
-
5
- module Phlexi
6
- module Table
7
- module Components
8
- module Options
9
- module Types
10
- def type(type = nil)
11
- if type.nil?
12
- options[:as] = options.fetch(:as) { inferred_db_type }
13
- else
14
- options[:as] = type
15
- self
16
- end
17
- end
18
-
19
- def inferred_db_type
20
- @inferred_db_type ||= infer_db_type
21
- end
22
-
23
- def inferred_display_component
24
- @inferred_display_component ||= infer_display_component
25
- end
26
-
27
- private
28
-
29
- def infer_display_component
30
- case type
31
- when :string, :text
32
- infer_string_display_type(key)
33
- when :integer, :float, :decimal
34
- :number
35
- when :date, :datetime, :time
36
- :date
37
- when :boolean
38
- :boolean
39
- when :json, :jsonb, :hstore
40
- :code
41
- else
42
- if association_reflection
43
- :association
44
- elsif attachment_reflection
45
- :attachment
46
- else
47
- :text
48
- end
49
- end
50
- end
51
-
52
- def infer_db_type
53
- if sample.class.respond_to?(:columns_hash)
54
- # ActiveRecord model
55
- column = sample.class.columns_hash[key.to_s]
56
- return column.type if column
57
- end
58
-
59
- if sample.class.respond_to?(:attribute_types)
60
- # ActiveModel::Attributes
61
- custom_type = sample.class.attribute_types[key.to_s]
62
- return custom_type.type if custom_type&.type
63
- end
64
-
65
- # Check if sample responds to the key
66
- if sample.respond_to?(key)
67
- # Fallback to inferring type from the value
68
- return infer_db_type_from_value(sample.send(key))
69
- end
70
-
71
- # Default to string if we can't determine the type
72
- :string
73
- end
74
-
75
- def infer_db_type_from_value(value)
76
- case value
77
- when Integer
78
- :integer
79
- when Float
80
- :float
81
- when BigDecimal
82
- :decimal
83
- when TrueClass, FalseClass
84
- :boolean
85
- when Date
86
- :date
87
- when Time, DateTime
88
- :datetime
89
- when Hash
90
- :json
91
- else
92
- :string
93
- end
94
- end
95
-
96
- def infer_string_display_type(key)
97
- key = key.to_s.downcase
98
-
99
- return :password if is_password_field?
100
-
101
- custom_type = custom_string_display_type(key)
102
- return custom_type if custom_type
103
-
104
- :text
105
- end
106
-
107
- def custom_string_display_type(key)
108
- custom_mappings = {
109
- /url$|^link|^site/ => :url,
110
- /^email/ => :email,
111
- /phone|tel(ephone)?/ => :phone,
112
- /^time/ => :time,
113
- /^date/ => :date,
114
- /^number|_count$|_amount$/ => :number,
115
- /^color/ => :color
116
- }
117
-
118
- custom_mappings.each do |pattern, type|
119
- return type if key.match?(pattern)
120
- end
121
-
122
- nil
123
- end
124
-
125
- def is_password_field?
126
- key = self.key.to_s.downcase
127
-
128
- exact_matches = ["password"]
129
- prefixes = ["encrypted_"]
130
- suffixes = ["_password", "_digest", "_hash"]
131
-
132
- exact_matches.include?(key) ||
133
- prefixes.any? { |prefix| key.start_with?(prefix) } ||
134
- suffixes.any? { |suffix| key.end_with?(suffix) }
135
- end
136
- end
137
- end
138
- end
139
- end
140
- end