organism-ui 0.2.1 → 0.2.16

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: 3065e937e87ba2c40e0b8a30d1c57402330b7c4452faea8d6220e7188906d2fd
4
- data.tar.gz: 30cee7eb57cc13b3002c328465c215040e9dbff0e8a86d915005200c46305352
3
+ metadata.gz: 45abc828f8e47547304444edd15b9ffb4ec4377feb286c5559fe4c60d6e23dfd
4
+ data.tar.gz: 411a58b849148a4f9c1635a8a318784bc25421a4b146a4911ce0bc4c1cec4dfb
5
5
  SHA512:
6
- metadata.gz: 2c314d87dc4192fd479015a1b6ae10ad238bb4e5a22b19c5d7a9fb5d31d6b16bd801dff97dbd26743b5931159dd6a3f92e88e3f3116d66a1860451c31bfda36a
7
- data.tar.gz: db8edc5cc1a98bb8deb6da1eae88b000d14211d561a47492d221eacbfd474e773e3ea267b71861d523db95b11739fa52ae0c7e83c87b3bce530a462e53ec0dcf
6
+ metadata.gz: db0d57b58f82cd7cf96aa9afad5f6862f7ce8b11652e383ca1ac13b5b38c4c1d360b4c6ad9bdbb66d28926f8c9cc66f657efc16ccab365ed5df8bbd3b6ce6649
7
+ data.tar.gz: d75702678ac862483be221af7bd4a3a19fc60e502767214a14688ca2710814b893a33c1a7907857d9b6631596f13dd24425e051148249bf569656a0c57f9fb1b
data/README.md CHANGED
@@ -1,14 +1,27 @@
1
- # Ui
2
- Short description and motivation.
1
+ # Organism Ui
2
+ Ui components made with cells (https://github.com/trailblazer/cells). This library is in ALPHA and subject to change anytime and dramatically before 1.0.
3
3
 
4
4
  ## Usage
5
- How to use my plugin.
5
+
6
+ ### Components
7
+ Components are just configurable cells (https://github.com/trailblazer/cells) for basic ui components. Inspired by ant.design.
8
+
9
+ You render components in your views or controllers:
10
+ ```ruby
11
+ <%= cell(
12
+ Ui::Buttons::Primary,
13
+ 'Primary Button',
14
+ path: '/'
15
+ ) %>
16
+ ```
17
+
18
+ You can see full examples of components in the style guide: https://github.com/nolantait/organism-ui/blob/master/app/views/ui/style_guide/show.html.erb
6
19
 
7
20
  ## Installation
8
21
  Add this line to your application's Gemfile:
9
22
 
10
23
  ```ruby
11
- gem 'ui'
24
+ gem 'organism-ui'
12
25
  ```
13
26
 
14
27
  And then execute:
@@ -18,9 +31,20 @@ $ bundle
18
31
 
19
32
  Or install it yourself as:
20
33
  ```bash
21
- $ gem install ui
34
+ $ gem install organism-ui
22
35
  ```
23
36
 
37
+ ## Style guide
38
+ To quickly style your components you can mount the engine and navigate to an example style guide.
39
+
40
+ ```ruby
41
+ Rails.application.routes.draw do
42
+ mount Ui::Engine => "/ui"
43
+ end
44
+ ```
45
+
46
+ You can then navigate to localhost:3000/ui/style_guide to see your components.
47
+
24
48
  ## Contributing
25
49
  Contribution directions go here.
26
50
 
@@ -674,11 +674,10 @@
674
674
  ).()
675
675
  }
676
676
  ],
677
- renderable: ->(item) {
677
+ item_renderer: ->(item) {
678
678
  content_tag(
679
679
  :div,
680
- [
681
- content_tag(:p, item),
680
+ content_tag(:p, item) +
682
681
  content_tag(
683
682
  :nav,
684
683
  cell(
@@ -687,8 +686,7 @@
687
686
  path: '#',
688
687
  size: :small
689
688
  ).call(:edit)
690
- )
691
- ].join(' ').html_safe,
689
+ ),
692
690
  class: 'flex flex-row justify-between items-center p-4'
693
691
  )
694
692
  }
@@ -727,6 +725,32 @@
727
725
  </div>
728
726
  </section>
729
727
 
728
+ <section class="style-guide__example" id="type">
729
+ <header>
730
+ <h2>Vertical</h2>
731
+ </header>
732
+
733
+ <div class="space-y-4">
734
+ <%= cell(
735
+ Ui::Table,
736
+ [
737
+ "Data 1",
738
+ "Data 2",
739
+ "Data 3",
740
+ ],
741
+ columns: [
742
+ ["", ->(data) { data } ],
743
+ ["Column 2", ->(data) { "Column 2 data" } ],
744
+ ["Column 3", ->(data) { "Column 3 data" } ],
745
+ ["Actions", ->(data) { cell(Ui::Buttons::Tertiary, 'More')} ],
746
+ ],
747
+ header: 'My title',
748
+ orientation: 'vertical',
749
+ style: 'my-style'
750
+ ).() %>
751
+ </div>
752
+ </section>
753
+
730
754
  <section class="style-guide__example" id="type">
731
755
  <header>
732
756
  <h2>Selectable</h2>
@@ -748,6 +772,8 @@
748
772
  ],
749
773
  header: 'Multi select',
750
774
  style: 'my-style',
775
+ row_renderer: ->(row, columns) {
776
+ },
751
777
  features: {
752
778
  selectable: {
753
779
  multiple: true
data/lib/ui.rb CHANGED
@@ -4,6 +4,8 @@ require "cells-erb"
4
4
  require "cells-rails"
5
5
  require 'dry-struct'
6
6
 
7
+ require "ui/errors/base"
8
+
7
9
  require "ui/types"
8
10
  require "ui/value"
9
11
 
data/lib/ui/actionable.rb CHANGED
@@ -1,11 +1,26 @@
1
1
  module Ui
2
2
  module Actionable
3
- def actions
4
- render_group(
5
- options.fetch(:actions, Array.new).map do |action|
6
- action.call(model)
7
- end
8
- )
3
+ Actions = Types::Array.default([].freeze).of(Types::Callable)
4
+
5
+ def actions(object = model)
6
+ content_tag(:nav, class: 'ui-actions', role: 'navigation') do
7
+ render_group(
8
+ actions_list.map do |action|
9
+ action.call(object)
10
+ end
11
+ )
12
+ end
13
+ end
14
+
15
+ def actions_list
16
+ begin
17
+ Actions[options.fetch(:actions, Array.new)]
18
+ rescue Dry::Types::ConstraintError
19
+ raise Ui::Errors::InvalidActions.new(
20
+ "Actions for #{self.class.to_s} are invalid. Ensure you are passing " \
21
+ "an array of callable objects that will be passed a model"
22
+ )
23
+ end
9
24
  end
10
25
 
11
26
  def actions_length
@@ -13,7 +28,7 @@ module Ui
13
28
  end
14
29
 
15
30
  def has_actions?
16
- options.fetch(:actions, []).any?
31
+ actions_list.any?
17
32
  end
18
33
  end
19
34
  end
@@ -1,9 +1,9 @@
1
1
  module Ui
2
2
  class Breadcrumbs < Component
3
+ include Stylable
4
+
3
5
  def show
4
- content_tag(:nav, class: 'ui-breadcrumbs') do
5
- breadcrumb_links
6
- end
6
+ content_tag(:nav, render_group(breadcrumb_links.flatten), class: style)
7
7
  end
8
8
 
9
9
  private
@@ -14,10 +14,10 @@ module Ui
14
14
 
15
15
  def breadcrumb_links
16
16
  breadcrumbs.map.with_index do |crumb, index|
17
- [item_renderer.call(crumb)].tap do |renderable|
18
- renderable.unshift(delimiter) unless index == 0
17
+ [item_renderer.call(crumb)].tap do |array|
18
+ array.unshift(delimiter) unless index == 0
19
19
  end
20
- end.flatten.join(' ').html_safe
20
+ end
21
21
  end
22
22
 
23
23
  def delimiter
@@ -25,7 +25,20 @@ module Ui
25
25
  end
26
26
 
27
27
  def item_renderer
28
- options[:item_renderer] || Ui::Breadcrumbs::Breadcrumb
28
+ options[:item_renderer] || default_item_renderer
29
+ end
30
+
31
+ def default_item_renderer
32
+ ->(item) {
33
+ cell(
34
+ Ui::Breadcrumbs::Breadcrumb,
35
+ item
36
+ ).()
37
+ }
38
+ end
39
+
40
+ def component_style
41
+ 'ui-breadcrumbs'
29
42
  end
30
43
  end
31
44
  end
@@ -1,6 +1,8 @@
1
1
  module Ui
2
2
  class Breadcrumbs < Component
3
3
  class Breadcrumb < Component
4
+ include Stylable
5
+
4
6
  property :name
5
7
  property :path
6
8
  property :current?
@@ -9,9 +11,7 @@ module Ui
9
11
  def show
10
12
  content_tag(
11
13
  :span,
12
- link_to(path) do
13
- title.html_safe
14
- end,
14
+ link_to(render_group(title), path),
15
15
  class: style
16
16
  )
17
17
  end
@@ -19,17 +19,19 @@ module Ui
19
19
  private
20
20
 
21
21
  def title
22
- [name].tap do |array|
23
- array.unshift(content_tag(:i, nil, class: icon)) if model.try(:icon)
24
- end.join(' ')
22
+ [content_tag(:span, name)].tap do |array|
23
+ array.unshift(content_tag(:i, nil, class: icon)) if has_icon?
24
+ end
25
25
  end
26
26
 
27
- def style
28
- [
29
- 'breadcrumb'
30
- ].tap do |array|
31
- array << 'breadcrumb--current' if current?
32
- end
27
+ def has_icon?
28
+ model.try(:icon)
29
+ end
30
+
31
+ def component_style
32
+ ['ui-breadcrumb'].tap do |array|
33
+ array << 'ui-breadcrumb--current' if current?
34
+ end.join(' ')
33
35
  end
34
36
  end
35
37
  end
@@ -1,6 +1,8 @@
1
1
  module Ui
2
2
  module Buttons
3
3
  class Base < Component
4
+ include Stylable
5
+
4
6
  def show
5
7
  display(
6
8
  text_with_icon(icon),
@@ -38,6 +40,22 @@ module Ui
38
40
  )
39
41
  end
40
42
 
43
+ def phone
44
+ display(
45
+ text_with_icon(phone_icon),
46
+ "tel:#{path}",
47
+ button_options
48
+ )
49
+ end
50
+
51
+ def email
52
+ mail_to(
53
+ path,
54
+ text_with_icon(email_icon),
55
+ button_options
56
+ )
57
+ end
58
+
41
59
  private
42
60
 
43
61
  def display(*args)
@@ -46,7 +64,7 @@ module Ui
46
64
  :button,
47
65
  args.first,
48
66
  disabled: true,
49
- class: button_classes
67
+ class: style
50
68
  )
51
69
  else
52
70
  if path == '#'
@@ -69,13 +87,12 @@ module Ui
69
87
  'fas fa-trash'
70
88
  end
71
89
 
72
- def button_classes
73
- [
74
- "button",
75
- style,
76
- size,
77
- options.fetch(:style, '')
78
- ].compact.join(' ')
90
+ def phone_icon
91
+ 'fas fa-phone'
92
+ end
93
+
94
+ def email_icon
95
+ 'fas fa-envelope'
79
96
  end
80
97
 
81
98
  def size
@@ -92,25 +109,40 @@ module Ui
92
109
  end
93
110
 
94
111
  def text_with_icon(icon)
95
- if icon
96
- content_tag(
97
- :span,
98
- render_group([
99
- content_tag(:i, nil, class: icon),
100
- text
101
- ].compact)
102
- )
103
- else
104
- text
112
+ order = [text].tap do |array|
113
+ case icon_position
114
+ when 'end'
115
+ array.push(display_icon(icon))
116
+ else
117
+ array.unshift(display_icon(icon))
118
+ end
105
119
  end
120
+
121
+ render_group(order)
122
+ end
123
+
124
+ def display_icon(icon)
125
+ content_tag(:i, nil, class: icon) unless icon.blank?
106
126
  end
107
127
 
108
- def style
109
- ''
128
+ def component_style
129
+ [
130
+ 'button',
131
+ size,
132
+ ].join(' ')
110
133
  end
111
134
 
112
135
  def icon
113
- options[:icon]
136
+ icon_options.fetch(:style, '')
137
+ end
138
+
139
+ def icon_position
140
+ icon_options.fetch(:position, 'start')
141
+ end
142
+
143
+ def icon_options
144
+ opts = options.fetch(:icon, {})
145
+ opts.is_a?(Hash) ? opts : { style: opts }
114
146
  end
115
147
 
116
148
  def path
@@ -135,7 +167,7 @@ module Ui
135
167
 
136
168
  def button_options
137
169
  {
138
- class: button_classes,
170
+ class: style,
139
171
  disabled: disabled?,
140
172
  data: data,
141
173
  method: method
@@ -3,8 +3,11 @@ module Ui
3
3
  class Primary < Base
4
4
  private
5
5
 
6
- def style
7
- 'button--primary'
6
+ def component_style
7
+ [
8
+ 'button--primary',
9
+ super
10
+ ].flatten
8
11
  end
9
12
  end
10
13
  end
@@ -3,8 +3,11 @@ module Ui
3
3
  class Secondary < Base
4
4
  private
5
5
 
6
- def style
7
- 'button--secondary'
6
+ def component_style
7
+ [
8
+ 'button--secondary',
9
+ super
10
+ ].flatten
8
11
  end
9
12
  end
10
13
  end
@@ -3,8 +3,11 @@ module Ui
3
3
  class Tertiary < Base
4
4
  private
5
5
 
6
- def style
7
- 'button--tertiary'
6
+ def component_style
7
+ [
8
+ 'button--tertiary',
9
+ super
10
+ ].flatten
8
11
  end
9
12
  end
10
13
  end
data/lib/ui/card.rb CHANGED
@@ -16,9 +16,7 @@ module Ui
16
16
  end
17
17
 
18
18
  def card_actions
19
- content_tag(:nav, class: "ui-card__controls") do
20
- actions
21
- end if has_actions?
19
+ actions if has_actions?
22
20
  end
23
21
 
24
22
  def title
data/lib/ui/collapse.rb CHANGED
@@ -13,7 +13,8 @@ module Ui
13
13
  def panels
14
14
  cell(
15
15
  Ui::Collapse::Panel,
16
- collection: model
16
+ collection: model,
17
+ actions: options[:actions]
17
18
  ).()
18
19
  end
19
20
 
@@ -1,6 +1,8 @@
1
1
  module Ui
2
2
  class Collapse < Component
3
3
  class Panel < Component
4
+ include Actionable
5
+
4
6
  def show
5
7
  render
6
8
  end
@@ -18,11 +20,11 @@ module Ui
18
20
  end
19
21
 
20
22
  def header
21
- content_tag(:p, display(model[0]))
23
+ display(model[0])
22
24
  end
23
25
 
24
26
  def content
25
- content_tag(:p, display(model[1]))
27
+ display(model[1])
26
28
  end
27
29
 
28
30
  def display(item)
@@ -1,16 +1,17 @@
1
1
  <article
2
2
  class="ui-collapse-panel"
3
3
  data-controller="collapsable"
4
- data-collapsable-collapsed-value="false"
4
+ data-collapsable-collapsed-value="true"
5
5
  data-collapsable-hidden-class="hidden"
6
6
  data-collapsable-collapsed-class="ui-collapsed">
7
7
 
8
- <header data-action="click->collapsable#toggle">
8
+ <header data-action="click->collapsable#toggle" class="ui-collapse-panel__header">
9
9
  <%= collapse_icon %>
10
10
  <%= header %>
11
+ <%= actions %>
11
12
  </header>
12
13
 
13
- <div data-collapsable-target="content" class="ui-collapse-panel__content">
14
+ <section data-collapsable-target="content" class="ui-collapse-panel__content">
14
15
  <%= content %>
15
- </div>
16
+ </section>
16
17
  </article>
data/lib/ui/component.rb CHANGED
@@ -6,10 +6,15 @@ module Ui
6
6
  include ActionView::Context
7
7
 
8
8
  VIEWPATH = Pathname.new(__FILE__).join("../..")
9
- self.view_paths = [VIEWPATH]
9
+ self.view_paths << VIEWPATH
10
10
 
11
11
  def capture(*args)
12
- yield(*args).html_safe
12
+ content = yield(*args)
13
+ if content.is_a?(String)
14
+ content.html_safe
15
+ else
16
+ content
17
+ end
13
18
  end
14
19
 
15
20
  def render_group(items)
@@ -25,14 +25,14 @@ module Ui
25
25
  content_tag(
26
26
  :header,
27
27
  render_group([
28
- content_tag(:h2, title),
29
- content_tag(:nav, actions)
28
+ options[:header],
29
+ actions
30
30
  ])
31
- ) if title || has_actions?
31
+ ) if display_header?
32
32
  end
33
33
 
34
- def title
35
- options[:title]
34
+ def display_header?
35
+ options[:header] || has_actions?
36
36
  end
37
37
 
38
38
  def items
@@ -5,19 +5,33 @@ module Ui
5
5
  content_tag(
6
6
  :div,
7
7
  render_group([
8
- content_tag(:dt, title),
9
- content_tag(:dd, value.html_safe)
8
+ content_tag(:dt, item_title),
9
+ content_tag(:dd, value)
10
10
  ]),
11
11
  class: 'ui-descriptive-list__item'
12
12
  )
13
13
  end
14
14
 
15
- def title
15
+ def value
16
+ render_group([
17
+ display(item_value)
18
+ ])
19
+ end
20
+
21
+ def display(value)
22
+ if value.is_a?(Proc)
23
+ value.call
24
+ else
25
+ value
26
+ end
27
+ end
28
+
29
+ def item_title
16
30
  model[0]
17
31
  end
18
32
 
19
- def value
20
- model[1].try(:call) || model[1]
33
+ def item_value
34
+ model[1]
21
35
  end
22
36
  end
23
37
  end
data/lib/ui/dropdown.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  module Ui
2
2
  class Dropdown < Component
3
+ include Stylable
4
+
3
5
  Modes = Types::String.enum(
4
6
  'click',
5
7
  'hover'
@@ -18,5 +20,9 @@ module Ui
18
20
  def mode
19
21
  Modes[options.fetch(:mode, 'click')]
20
22
  end
23
+
24
+ def component_style
25
+ "ui-dropdown"
26
+ end
21
27
  end
22
28
  end
@@ -4,7 +4,7 @@
4
4
  data-dropdown-expanded-value="false"
5
5
  data-dropdown-mode-value="<%= mode %>"
6
6
  data-action="click->dropdown#toggle"
7
- class="ui-dropdown">
7
+ class="<%= style %>">
8
8
  <%= yield %>
9
9
 
10
10
  <div data-dropdown-target="expandable" class="ui-dropdown__expandable">
@@ -4,8 +4,6 @@
4
4
 
5
5
  <figcaption>
6
6
  <%= caption %>
7
- <nav>
8
- <%= actions %>
9
- </nav>
7
+ <%= actions %>
10
8
  </figcaption>
11
9
  </figure>
data/lib/ui/engine.rb CHANGED
@@ -2,6 +2,8 @@ module Ui
2
2
  class Engine < ::Rails::Engine
3
3
  isolate_namespace Ui
4
4
 
5
+ config.autoload_paths << "#{config.root}/lib"
6
+
5
7
  config.generators do |g|
6
8
  g.test_framework :rspec, fixture: false
7
9
  g.fixture_replacement :factory_bot
@@ -0,0 +1,6 @@
1
+ module Ui
2
+ module Errors
3
+ class Base < StandardError
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Ui
2
+ module Errors
3
+ class InvalidActions < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Ui
2
+ module Errors
3
+ class InvalidListItems < Base
4
+ end
5
+ end
6
+ end
data/lib/ui/list.rb CHANGED
@@ -4,6 +4,7 @@ module Ui
4
4
  include Actionable
5
5
 
6
6
  Renderable = Types.Interface(:call)
7
+ ListItems = Types.Interface(:each, :map, :any?)
7
8
 
8
9
  def show
9
10
  render
@@ -11,21 +12,32 @@ module Ui
11
12
 
12
13
  private
13
14
 
15
+ def list_data
16
+ begin
17
+ ListItems[model]
18
+ rescue Dry::Types::ConstraintError
19
+ raise Ui::Errors::InvalidListItems.new(
20
+ "List items for #{self.class.to_s} are invalid. Ensure you are passing " \
21
+ "an empty array or array of items that will be passed to the item renderer"
22
+ )
23
+ end
24
+ end
25
+
14
26
  def list
15
27
  content_tag(:ul, list_items)
16
28
  end
17
29
 
18
30
  def list_items
19
- if list_data.any?
20
- render_group(list_data)
31
+ if rendered_items.any?
32
+ render_group(rendered_items)
21
33
  else
22
34
  render_empty
23
35
  end
24
36
  end
25
37
 
26
- def list_data
27
- model.map do |item|
28
- renderable.call(item)
38
+ def rendered_items
39
+ list_data.map do |item|
40
+ item_renderer.call(item)
29
41
  end
30
42
  end
31
43
 
@@ -46,8 +58,8 @@ module Ui
46
58
  ) if options[:footer]
47
59
  end
48
60
 
49
- def renderable
50
- Renderable[options.fetch(:renderable, default_renderable)]
61
+ def item_renderer
62
+ Renderable[options.fetch(:item_renderer, default_renderable)]
51
63
  end
52
64
 
53
65
  def default_renderable
@@ -68,6 +80,10 @@ module Ui
68
80
  end
69
81
 
70
82
  def empty
83
+ options.fetch(:empty, default_empty)
84
+ end
85
+
86
+ def default_empty
71
87
  cell(
72
88
  Ui::Empty,
73
89
  nil
data/lib/ui/menu/item.rb CHANGED
@@ -24,7 +24,7 @@ module Ui
24
24
  private
25
25
 
26
26
  def render_item
27
- model.html_safe
27
+ model
28
28
  end
29
29
 
30
30
  def depth
@@ -9,7 +9,7 @@ module Ui
9
9
  :ul,
10
10
  render_group([
11
11
  previous_window,
12
- page_links.html_safe,
12
+ page_links,
13
13
  next_window
14
14
  ]),
15
15
  class: 'ui-pagination__window',
@@ -58,15 +58,17 @@ module Ui
58
58
 
59
59
 
60
60
  def page_links
61
- pages.inject('') do |content, page|
62
- content += content_tag(
63
- :li,
64
- cell(
65
- Ui::Pagination::PageLink,
66
- page
67
- ).()
68
- )
69
- end
61
+ render_group(
62
+ pages.map do |page|
63
+ content_tag(
64
+ :li,
65
+ cell(
66
+ Ui::Pagination::PageLink,
67
+ page
68
+ ).()
69
+ )
70
+ end
71
+ )
70
72
  end
71
73
 
72
74
  def last_window?
data/lib/ui/table.rb CHANGED
@@ -1,10 +1,21 @@
1
1
  require "ui/table/header"
2
2
  require "ui/table/row"
3
+ require "ui/table/vertical"
3
4
 
4
5
  module Ui
5
6
  class Table < Component
6
7
  include Actionable
7
8
  include Stylable
9
+ include ::Cell::Builder
10
+
11
+ builds do |model, options|
12
+ case options.fetch(:orientation, 'horizontal')
13
+ when 'vertical'
14
+ Ui::Table::Vertical
15
+ else
16
+ self
17
+ end
18
+ end
8
19
 
9
20
  def show
10
21
  render
@@ -22,6 +33,20 @@ module Ui
22
33
  end
23
34
 
24
35
  def table_headers
36
+ custom_header_renderer.is_a?(Proc) ?
37
+ custom_table_headers :
38
+ default_table_headers
39
+ end
40
+
41
+ def custom_table_headers
42
+ render_group(
43
+ columns.map do |column|
44
+ custom_header_renderer.call(column)
45
+ end
46
+ )
47
+ end
48
+
49
+ def default_table_headers
25
50
  content_tag(:tr) do
26
51
  cell(
27
52
  Ui::Table::Header,
@@ -31,31 +56,53 @@ module Ui
31
56
  end
32
57
 
33
58
  def table_rows
34
- if rows.any?
35
- cell(
36
- Ui::Table::Row,
37
- collection: rows,
38
- columns: columns
39
- )
59
+ if model.any?
60
+ custom_row_renderer.is_a?(Proc) ?
61
+ custom_table_rows :
62
+ default_table_rows
40
63
  else
41
64
  render_empty
42
65
  end
43
66
  end
44
67
 
68
+ def custom_table_rows
69
+ render_group(
70
+ model.map do |row|
71
+ custom_row_renderer.call(row, columns)
72
+ end
73
+ )
74
+ end
75
+
76
+ def default_table_rows
77
+ cell(
78
+ Ui::Table::Row,
79
+ collection: model,
80
+ columns: columns
81
+ ).()
82
+ end
83
+
45
84
  def table_data_attributes
46
85
  {
47
86
  controller: table_controllers,
48
- "selectable-selected-value": "[]",
49
- "selectable-type-value": multi_select? ? 'many' : 'one'
50
- }
87
+ }.tap do |hash|
88
+ if selectable?
89
+ hash["selectable-selected-value"] = "[]"
90
+ hash["selectable-type-value"] = multi_select? ? 'many' : 'one'
91
+ end
92
+ end
51
93
  end
52
94
 
53
95
  def table_body_data_attributes
54
96
  {
55
97
  controller: table_body_controllers,
56
- "sortable-update-url-value": sortable_options.fetch(:update_url, '#'),
57
- "sortable-input-name-value": sortable_options.fetch(:input_name, "object[position]")
58
- }
98
+ }.tap do |hash|
99
+ if sortable?
100
+ hash["sortable-update-url-value"] =
101
+ sortable_options.fetch(:update_url, '#')
102
+ hash["sortable-input-name-value"] =
103
+ sortable_options.fetch(:input_name, "object[position]")
104
+ end
105
+ end
59
106
  end
60
107
 
61
108
  def table_controllers
@@ -87,10 +134,6 @@ module Ui
87
134
  ) if options[:footer]
88
135
  end
89
136
 
90
- def component_style
91
- "ui-table"
92
- end
93
-
94
137
  def columns
95
138
  @columns ||= options.fetch(:columns, Array.new).tap do |columns|
96
139
  columns.unshift(selectable_column) if selectable?
@@ -140,8 +183,12 @@ module Ui
140
183
  options.fetch(:features, Hash.new)
141
184
  end
142
185
 
143
- def rows
144
- model
186
+ def custom_row_renderer
187
+ options.fetch(:row_renderer, nil)
188
+ end
189
+
190
+ def custom_header_renderer
191
+ options.fetch(:header_renderer, nil)
145
192
  end
146
193
 
147
194
  def render_empty
@@ -158,5 +205,9 @@ module Ui
158
205
  colspan: columns.size
159
206
  )
160
207
  end
208
+
209
+ def component_style
210
+ "ui-table ui-table--horizontal"
211
+ end
161
212
  end
162
213
  end
@@ -1,20 +1,30 @@
1
1
  module Ui
2
2
  class Table < Component
3
3
  class Header < Component
4
+ include Stylable
5
+
4
6
  def show
5
- content_tag(:th, title)
7
+ content_tag(:th, title, class: style)
6
8
  end
7
9
 
8
10
  private
9
11
 
12
+ def component_style
13
+ 'ui-table__header'
14
+ end
15
+
10
16
  def title
11
17
  case
12
- when model[0].is_a?(Proc)
13
- model[0].call
18
+ when column_title.is_a?(Proc)
19
+ column_title.call
14
20
  else
15
- model[0]
21
+ column_title
16
22
  end
17
23
  end
24
+
25
+ def column_title
26
+ model[0]
27
+ end
18
28
  end
19
29
  end
20
30
  end
data/lib/ui/table/row.rb CHANGED
@@ -1,12 +1,18 @@
1
1
  module Ui
2
2
  class Table < Component
3
3
  class Row < Component
4
+ include Stylable
5
+
4
6
  def show
5
- content_tag(:tr, render_group(table_data))
7
+ content_tag(:tr, render_group(table_data), class: style)
6
8
  end
7
9
 
8
10
  private
9
11
 
12
+ def component_style
13
+ 'ui-table__row'
14
+ end
15
+
10
16
  def table_data
11
17
  columns.map do |column|
12
18
  content_tag(:td, apply(column))
@@ -0,0 +1,45 @@
1
+ module Ui
2
+ class Table < Component
3
+ class Vertical < Table
4
+
5
+ private
6
+
7
+ def table_rows
8
+ if model.any?
9
+ cell(
10
+ row_renderer,
11
+ collection: columns[1..-1],
12
+ data: model
13
+ )
14
+ else
15
+ render_empty
16
+ end
17
+ end
18
+
19
+ def table_headers
20
+ content_tag(:tr) do
21
+ render_group([
22
+ content_tag(:th, columns[0].try(:first)),
23
+ cell(
24
+ header_renderer,
25
+ collection: model,
26
+ column: columns[0],
27
+ )
28
+ ])
29
+ end
30
+ end
31
+
32
+ def row_renderer
33
+ Ui::Table::Vertical::Row
34
+ end
35
+
36
+ def header_renderer
37
+ Ui::Table::Vertical::Header
38
+ end
39
+
40
+ def component_style
41
+ "ui-table ui-table--vertical"
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,26 @@
1
+ module Ui
2
+ class Table < Component
3
+ class Vertical < Table
4
+ class Header < Ui::Table::Header
5
+ def show
6
+ content_tag(:th, title)
7
+ end
8
+
9
+ private
10
+
11
+ def title
12
+ case
13
+ when column[1].is_a?(Proc)
14
+ column[1].call(model)
15
+ else
16
+ model.to_s
17
+ end
18
+ end
19
+
20
+ def column
21
+ options[:column]
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,34 @@
1
+ module Ui
2
+ class Table < Component
3
+ class Vertical < Table
4
+ class Row < Ui::Table::Row
5
+
6
+ private
7
+
8
+ def table_data
9
+ data.map do |item|
10
+ content_tag(:td, apply(item))
11
+ end.tap do |array|
12
+ array.unshift(content_tag(:th, column_title))
13
+ end
14
+ end
15
+
16
+ def apply(item)
17
+ column[1].call(item)
18
+ end
19
+
20
+ def column
21
+ model
22
+ end
23
+
24
+ def column_title
25
+ column[0]
26
+ end
27
+
28
+ def data
29
+ options.fetch(:data, Array.new)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
data/lib/ui/types.rb CHANGED
@@ -3,5 +3,7 @@ require 'dry-types'
3
3
  module Ui
4
4
  module Types
5
5
  include Dry.Types()
6
+
7
+ Callable = Types.Interface(:call)
6
8
  end
7
9
  end
data/lib/ui/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ui
2
- VERSION = '0.2.1'
2
+ VERSION = '0.2.16'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: organism-ui
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nolan Tait
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-13 00:00:00.000000000 Z
11
+ date: 2021-03-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -156,6 +156,20 @@ dependencies:
156
156
  - - "~>"
157
157
  - !ruby/object:Gem::Version
158
158
  version: 11.1.3
159
+ - !ruby/object:Gem::Dependency
160
+ name: sqlite3
161
+ requirement: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - "~>"
164
+ - !ruby/object:Gem::Version
165
+ version: 1.4.2
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - "~>"
171
+ - !ruby/object:Gem::Version
172
+ version: 1.4.2
159
173
  description: A collection of ui components implemented in cells.
160
174
  email:
161
175
  - nolanjtait@gmail.com
@@ -201,6 +215,9 @@ files:
201
215
  - lib/ui/empty.rb
202
216
  - lib/ui/empty/show.erb
203
217
  - lib/ui/engine.rb
218
+ - lib/ui/errors/base.rb
219
+ - lib/ui/errors/invalid_actions.rb
220
+ - lib/ui/errors/invalid_list_items.rb
204
221
  - lib/ui/list.rb
205
222
  - lib/ui/list/item.rb
206
223
  - lib/ui/list/show.erb
@@ -231,6 +248,9 @@ files:
231
248
  - lib/ui/table/select_all.rb
232
249
  - lib/ui/table/show.erb
233
250
  - lib/ui/table/sort.rb
251
+ - lib/ui/table/vertical.rb
252
+ - lib/ui/table/vertical/header.rb
253
+ - lib/ui/table/vertical/row.rb
234
254
  - lib/ui/tooltip.rb
235
255
  - lib/ui/tooltip/show.erb
236
256
  - lib/ui/types.rb
@@ -243,7 +263,7 @@ homepage: https://github.com/nolantait/organism-ui
243
263
  licenses:
244
264
  - MIT
245
265
  metadata: {}
246
- post_install_message:
266
+ post_install_message:
247
267
  rdoc_options: []
248
268
  require_paths:
249
269
  - lib
@@ -259,7 +279,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
259
279
  version: '0'
260
280
  requirements: []
261
281
  rubygems_version: 3.1.4
262
- signing_key:
282
+ signing_key:
263
283
  specification_version: 4
264
284
  summary: A collection of ui components implemented in cells.
265
285
  test_files: []