phlexi-table 0.0.2 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a2fc89d8ce811c592ca3a145af7ce3c91171d767404ec497a117a609e26c2f6a
4
- data.tar.gz: 72d3289f57300d9f05a717cc9745d223971c0c143a9245e6e8a54c0ed5b6303c
3
+ metadata.gz: c7f2796fd0b9bc9cd244f59185007f05e84c69611b24d0fa5f560b4cc3faad58
4
+ data.tar.gz: 5f33756a70709a8b640a830fae776eb6afa16681acef0e430a69194b1fa116a6
5
5
  SHA512:
6
- metadata.gz: 5aab0ea7be94c1f55a554b10b21710d2e4c6dd98ad0f9e1e1671660a03327e569163acaad34ae6ba1f57f7f5f0759ff58d73e553d366f64d939e4ecea9b53bed
7
- data.tar.gz: 8132fba9adc5135022108759ff28ba5cd568ee818e307ce5fc0f36c11f19715b170af523fb4c90856ee718f2c29415fba8b7a281dc4125e365042f9ce54972fa
6
+ metadata.gz: f319147d3387d048567c1f6d0441dcf4849baabc56a183019897552796a905a88da59ec475a9b8a4aa3baca038973fce4cd98225ca0060879a7813bc0d2272f5
7
+ data.tar.gz: 419002167057a8ee7fa4e69aedc07d871b026bdbd5c32f15c0d286647e604c5dc4e081c1ff515e0eee66768160df9226289da465ed27c1b71dc1e0e76402eac0
@@ -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,83 @@
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
+ sort_icon_inactive = themed(:sort_icon_inactive)
25
+
26
+ span(class: themed(:header_cell_sort_indicator)) {
27
+ svg(
28
+ class: tokens(
29
+ sort_icon,
30
+ -> { @sort_params[:direction] == "ASC" } => sort_icon_active,
31
+ -> { @sort_params[:direction] != "ASC" } => sort_icon_inactive
32
+ ),
33
+ aria_hidden: "true",
34
+ xmlns: "http://www.w3.org/2000/svg",
35
+ fill: "none",
36
+ viewbox: "0 0 10 6"
37
+ ) do |s|
38
+ s.path(
39
+ stroke: "currentColor",
40
+ stroke_linecap: "round",
41
+ stroke_linejoin: "round",
42
+ stroke_width: "2",
43
+ d: "M9 5 5 1 1 5"
44
+ )
45
+ end
46
+ svg(
47
+ class: tokens(
48
+ sort_icon,
49
+ -> { @sort_params[:direction] == "DESC" } => sort_icon_active,
50
+ -> { @sort_params[:direction] != "DESC" } => sort_icon_inactive
51
+ ),
52
+ aria_hidden: "true",
53
+ xmlns: "http://www.w3.org/2000/svg",
54
+ fill: "none",
55
+ viewbox: "0 0 10 6"
56
+ ) do |s|
57
+ s.path(
58
+ stroke: "currentColor",
59
+ stroke_linecap: "round",
60
+ stroke_linejoin: "round",
61
+ stroke_width: "2",
62
+ d: "M1 1 5 5 9 1"
63
+ )
64
+ end
65
+ }
66
+ end
67
+
68
+ next if @sort_params[:position].nil?
69
+
70
+ sort_index_clear_link = themed(:sort_index_clear_link)
71
+ sort_index_clear_link_text = themed(:sort_index_clear_link_text)
72
+ sort_index_clear_link_icon = themed(:sort_index_clear_link_icon)
73
+
74
+ a(href: @sort_params[:reset_url], title: "Clear sort", class: sort_index_clear_link) {
75
+ span(class: sort_index_clear_link_text) { (@sort_params[:position] + 1).to_s }
76
+ span(class: sort_index_clear_link_icon) { "✕" }
77
+ }
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ 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,33 @@
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
+ header_cell_content_wrapper: nil,
22
+ header_cell_sort_wrapper: nil,
23
+ sort_icon: nil,
24
+ sort_icon_active: nil,
25
+ sort_icon_inactive: nil,
26
+ header_cell_sort_indicator: nil,
27
+ sort_index_clear_link: nil,
28
+ sort_index_clear_link_text: nil,
29
+ sort_index_clear_link_icon: nil
30
+ }.freeze
26
31
  end
27
32
  end
28
33
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Phlexi
4
4
  module Table
5
- VERSION = "0.0.2"
5
+ VERSION = "0.0.4"
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.4
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-22 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