phlexi-table 0.0.1

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 (42) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.ruby-version +1 -0
  4. data/Appraisals +8 -0
  5. data/CHANGELOG.md +5 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +13 -0
  8. data/Rakefile +14 -0
  9. data/TODO +0 -0
  10. data/config.ru +6 -0
  11. data/gemfiles/default.gemfile +5 -0
  12. data/gemfiles/rails_7.gemfile +8 -0
  13. data/lib/phlexi/table/base.rb +119 -0
  14. data/lib/phlexi/table/components/base.rb +38 -0
  15. data/lib/phlexi/table/components/concerns/displays_value.rb +54 -0
  16. data/lib/phlexi/table/components/date_time.rb +49 -0
  17. data/lib/phlexi/table/components/description.rb +21 -0
  18. data/lib/phlexi/table/components/hint.rb +21 -0
  19. data/lib/phlexi/table/components/label.rb +15 -0
  20. data/lib/phlexi/table/components/number.rb +37 -0
  21. data/lib/phlexi/table/components/placeholder.rb +15 -0
  22. data/lib/phlexi/table/components/string.rb +17 -0
  23. data/lib/phlexi/table/components/wrapper.rb +17 -0
  24. data/lib/phlexi/table/field_options/associations.rb +21 -0
  25. data/lib/phlexi/table/field_options/attachments.rb +21 -0
  26. data/lib/phlexi/table/field_options/description.rb +22 -0
  27. data/lib/phlexi/table/field_options/hints.rb +22 -0
  28. data/lib/phlexi/table/field_options/inferred_types.rb +129 -0
  29. data/lib/phlexi/table/field_options/labels.rb +28 -0
  30. data/lib/phlexi/table/field_options/placeholders.rb +18 -0
  31. data/lib/phlexi/table/field_options/themes.rb +132 -0
  32. data/lib/phlexi/table/structure/dom.rb +42 -0
  33. data/lib/phlexi/table/structure/field_builder.rb +158 -0
  34. data/lib/phlexi/table/structure/field_collection.rb +39 -0
  35. data/lib/phlexi/table/structure/namespace.rb +123 -0
  36. data/lib/phlexi/table/structure/namespace_collection.rb +40 -0
  37. data/lib/phlexi/table/structure/node.rb +24 -0
  38. data/lib/phlexi/table/version.rb +7 -0
  39. data/lib/phlexi/table.rb +30 -0
  40. data/lib/phlexi-table.rb +3 -0
  41. data/sig/phlexi/table.rbs +6 -0
  42. metadata +241 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e05e322aef835f61e4d9c75e678c54ed3abd96675b7eaedb7db6b8138f826450
4
+ data.tar.gz: 3d2e8b90865ab5e8e5b5b405046277a51177508187f3fde2d708612bed01dc6f
5
+ SHA512:
6
+ metadata.gz: e9e99ffd0dff1b5e92cdc779c8cd3fd5dee46e20094916e50eeec337c1af2b88fd0b9fa637dd56f54ad3a12381e0d2b2434747d536a4bb5fff928d08ccd6dd1f
7
+ data.tar.gz: 4f97e0de92ea6e09b17d7e09c6d242ee968638c6d4766991515aa54d3e738a51219190ca4d1fd944205b06b627eb9c3a2b0e7125adf5cb22eda839f14a5c7668
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.2.2
data/Appraisals ADDED
@@ -0,0 +1,8 @@
1
+ appraise "default" do
2
+ # gem "phlex", "~> 1.10"
3
+ end
4
+
5
+ appraise "rails-7" do
6
+ gem "rails", "~> 7.1.3", ">= 7.1.3.4"
7
+ gem "sqlite3", "~> 1.4"
8
+ end
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.2.0] - 2024-07-31
4
+
5
+ - Initial release
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Stefan Froelich
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,13 @@
1
+ # Phlexi::Table
2
+
3
+ Phlexi::Table is a flexible and powerful table builder for Ruby applications. It provides a more customizable and extensible way to create tables.
4
+
5
+ [![Ruby](https://github.com/radioactive-labs/phlexi-display/actions/workflows/main.yml/badge.svg)](https://github.com/radioactive-labs/phlexi-display/actions/workflows/main.yml)
6
+
7
+ ## Contributing
8
+
9
+ Bug reports and pull requests are welcome on GitHub at https://github.com/radioactive-labs/phlexi-display.
10
+
11
+ ## License
12
+
13
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+ require "standard/rake"
6
+
7
+ task default: %i[test standard]
8
+
9
+ # https://juincc.medium.com/how-to-setup-minitest-for-your-gems-development-f29c4bee13c2
10
+ Rake::TestTask.new do |t|
11
+ t.libs << "test"
12
+ t.test_files = FileList["test/**/*_test.rb"]
13
+ t.verbose = true
14
+ end
data/TODO ADDED
File without changes
data/config.ru ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubygems"
4
+ require "bundler"
5
+
6
+ Bundler.require :default, :development
@@ -0,0 +1,5 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 7.1.3", ">= 7.1.3.4"
6
+ gem "sqlite3", "~> 1.4"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/delegation"
4
+ require "active_support/core_ext/string/inflections"
5
+
6
+ module Phlexi
7
+ module Table
8
+ # A display component for rendering flexible and customizable data views.
9
+ #
10
+ # @example Basic usage
11
+ # Phlexi::Table.new(user) do |d|
12
+ # render d.field(:name).text
13
+ # render d.field(:email).text
14
+ # end
15
+ #
16
+ # @attr_reader [Symbol] key The display's key, derived from the record or explicitly set
17
+ # @attr_reader [ActiveModel::Model, nil] object The display's associated object
18
+ class Base < COMPONENT_BASE
19
+ class Namespace < Structure::Namespace; end
20
+
21
+ class FieldBuilder < Structure::FieldBuilder; end
22
+
23
+ attr_reader :key, :object
24
+
25
+ delegate :field, :nest_one, :nest_many, to: :@namespace
26
+
27
+ # Initializes a new Table instance.
28
+ #
29
+ # @param record [ActiveModel::Model, Symbol, String] The display's associated record or key
30
+ # @param attributes [Hash] Additional HTML attributes for the display container
31
+ # @param options [Hash] Additional options for display configuration
32
+ # @option options [String] :class CSS classes for the display
33
+ # @option options [Class] :namespace_klass Custom namespace class
34
+ # @option options [Class] :builder_klass Custom field builder class
35
+ def initialize(record, attributes: {}, **options)
36
+ @display_class = options.delete(:class)
37
+ @attributes = attributes
38
+ @namespace_klass = options.delete(:namespace_klass) || default_namespace_klass
39
+ @builder_klass = options.delete(:builder_klass) || default_builder_klass
40
+ @options = options
41
+
42
+ initialize_object_and_key(record)
43
+ initialize_namespace
44
+ end
45
+
46
+ # Renders the display template.
47
+ #
48
+ # @return [void]
49
+ def view_template
50
+ display_template
51
+ end
52
+
53
+ # Executes the display's content block.
54
+ # Override this in subclasses to define a static display.
55
+ #
56
+ # @return [void]
57
+ def display_template
58
+ instance_exec(&@_content_block) if @_content_block
59
+ end
60
+
61
+ protected
62
+
63
+ attr_reader :options, :attributes, :namespace_klass, :builder_klass
64
+
65
+ # Initializes the object and key based on the given record.
66
+ #
67
+ # @param record [ActiveModel::Model, Symbol, String] The display's associated record or key
68
+ # @return [void]
69
+ def initialize_object_and_key(record)
70
+ @key = options.delete(:key) || options.delete(:as)
71
+
72
+ case record
73
+ when String, Symbol
74
+ @object = nil
75
+ @key = record
76
+ else
77
+ @object = record
78
+ @key = if @key.nil? && object.respond_to?(:model_name) && object.model_name.respond_to?(:param_key) && object.model_name.param_key.present?
79
+ object.model_name.param_key
80
+ else
81
+ :object
82
+ end
83
+ end
84
+ @key = @key.to_sym
85
+ end
86
+
87
+ # Initializes the namespace for the display.
88
+ #
89
+ # @return [void]
90
+ def initialize_namespace
91
+ @namespace = namespace_klass.root(key, object: object, builder_klass: builder_klass)
92
+ end
93
+ # Retrieves the display's CSS classes.
94
+ #
95
+ # @return [String] The display's CSS classes
96
+ attr_reader :display_class
97
+
98
+ # Generates the display attributes hash.
99
+ #
100
+ # @return [Hash] The display attributes
101
+ def display_attributes
102
+ mix({
103
+ id: @namespace.dom_id,
104
+ class: display_class
105
+ }, attributes)
106
+ end
107
+
108
+ private
109
+
110
+ def default_namespace_klass
111
+ self.class::Namespace
112
+ end
113
+
114
+ def default_builder_klass
115
+ self.class::FieldBuilder
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Table
5
+ module Components
6
+ class Base < COMPONENT_BASE
7
+ attr_reader :field, :attributes
8
+
9
+ def initialize(field, **attributes)
10
+ @field = field
11
+ @attributes = attributes
12
+
13
+ build_attributes
14
+ append_attribute_classes
15
+ end
16
+
17
+ protected
18
+
19
+ def build_attributes
20
+ attributes.fetch(:id) { attributes[:id] = "#{field.dom.id}_#{component_name}" }
21
+ end
22
+
23
+ def append_attribute_classes
24
+ return if attributes[:class] == false
25
+
26
+ attributes[:class] = tokens(
27
+ component_name,
28
+ attributes[:class]
29
+ )
30
+ end
31
+
32
+ def component_name
33
+ @component_name ||= self.class.name.demodulize.underscore
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Table
5
+ module Components
6
+ module Concerns
7
+ module TablesValue
8
+ def view_template
9
+ value = normalize_value(field.value)
10
+ if value.blank?
11
+ render field.placeholder_tag(**@placeholder_attributes)
12
+ else
13
+ render_value(value)
14
+ end
15
+ end
16
+
17
+ # Renders the field value for display.
18
+ #
19
+ # @return [String] the formatted field value for display.
20
+ def render_value(value)
21
+ raise NotImplementedError, "#{self.class}#render_value"
22
+ # format_value()
23
+ end
24
+
25
+ protected
26
+
27
+ def build_attributes
28
+ super
29
+
30
+ @placeholder_attributes = attributes.delete(:placeholder_attributes) || {}
31
+ attributes[:id] = field.dom.id if attributes[:id] == "#{field.dom.id}_#{component_name}"
32
+ end
33
+
34
+ # def format_value(value)
35
+ # case value
36
+ # when Array
37
+ # format_array_value(value)
38
+ # else
39
+ # format_single_value(value)
40
+ # end
41
+ # end
42
+
43
+ # def format_array_value(array)
44
+ # array.map { |item| format_single_value(item) }.join(", ")
45
+ # end
46
+
47
+ def normalize_value(value)
48
+ value.to_s
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Table
5
+ module Components
6
+ class DateTime < Base
7
+ include Concerns::TablesValue
8
+
9
+ # Renders the date time value
10
+ #
11
+ # @param value [String, Date, Time, DateTime] The value to be rendered
12
+ # @return [void]
13
+ def render_value(value)
14
+ formatted_value = format_date_time(value)
15
+ p(**attributes) { formatted_value }
16
+ end
17
+
18
+ protected
19
+
20
+ def build_attributes
21
+ super
22
+
23
+ @options = {
24
+ format: default_format
25
+ }.merge(attributes.delete(:options) || {}).compact
26
+ end
27
+
28
+ private
29
+
30
+ def format_date_time(value)
31
+ I18n.l(value, **@options)
32
+ end
33
+
34
+ def default_format
35
+ :long
36
+ end
37
+
38
+ def normalize_value(value)
39
+ case value
40
+ when Date, DateTime, Time, nil
41
+ value
42
+ else
43
+ raise ArgumentError, "Value must be a Date, DateTime or Time object. #{value.inspect} given."
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Table
5
+ module Components
6
+ class Description < Base
7
+ def view_template
8
+ p(**attributes) {
9
+ field.description
10
+ }
11
+ end
12
+
13
+ private
14
+
15
+ def render?
16
+ field.has_description?
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Table
5
+ module Components
6
+ class Hint < Base
7
+ def view_template
8
+ p(**attributes) do
9
+ field.hint
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def render?
16
+ field.has_hint?
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Table
5
+ module Components
6
+ class Label < Base
7
+ def view_template
8
+ h5(**attributes) {
9
+ field.label
10
+ }
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/number_helper"
4
+
5
+ module Phlexi
6
+ module Table
7
+ module Components
8
+ class Number < Base
9
+ include Concerns::TablesValue
10
+
11
+ def render_value(value)
12
+ p(**attributes) {
13
+ format_number(value)
14
+ }
15
+ end
16
+
17
+ protected
18
+
19
+ def build_attributes
20
+ super
21
+
22
+ @options = attributes.delete(:options) || {}
23
+ end
24
+
25
+ private
26
+
27
+ def format_number(value)
28
+ ActiveSupport::NumberHelper.number_to_delimited(value, **@options)
29
+ end
30
+
31
+ def normalize_value(value)
32
+ Float(value.to_s)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Table
5
+ module Components
6
+ class Placeholder < Base
7
+ def view_template
8
+ p(**attributes) {
9
+ field.placeholder
10
+ }
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Table
5
+ module Components
6
+ class String < Base
7
+ include Concerns::TablesValue
8
+
9
+ def render_value(value)
10
+ p(**attributes) {
11
+ value
12
+ }
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Table
5
+ module Components
6
+ class Wrapper < Base
7
+ def view_template
8
+ div(**attributes) {
9
+ render field.label_tag
10
+ yield field if block_given?
11
+ render field.description_tag
12
+ }
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 FieldOptions
6
+ module Associations
7
+ protected
8
+
9
+ def association_reflection
10
+ @association_reflection ||= find_association_reflection
11
+ end
12
+
13
+ def find_association_reflection
14
+ if object.class.respond_to?(:reflect_on_association)
15
+ object.class.reflect_on_association(key)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Table
5
+ module FieldOptions
6
+ module Attachments
7
+ protected
8
+
9
+ def attachment_reflection
10
+ @attachment_reflection ||= find_attachment_reflection
11
+ end
12
+
13
+ def find_attachment_reflection
14
+ if object.class.respond_to?(:reflect_on_attachment)
15
+ object.class.reflect_on_attachment(key)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Table
5
+ module FieldOptions
6
+ module Description
7
+ def description(description = nil)
8
+ if description.nil?
9
+ options[:description]
10
+ else
11
+ options[:description] = description
12
+ self
13
+ end
14
+ end
15
+
16
+ def has_description?
17
+ description.present?
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Table
5
+ module FieldOptions
6
+ module Hints
7
+ def hint(hint = nil)
8
+ if hint.nil?
9
+ options[:hint]
10
+ else
11
+ options[:hint] = hint
12
+ self
13
+ end
14
+ end
15
+
16
+ def has_hint?
17
+ hint.present?
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end