lookbook 1.4.0 → 1.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/app/components/lookbook/nav/component.rb +1 -1
  3. data/app/components/lookbook/nav/directory/component.html.erb +2 -0
  4. data/app/components/lookbook/nav/entity/component.html.erb +2 -0
  5. data/app/components/lookbook/nav/entity/component.rb +1 -1
  6. data/app/components/lookbook/nav/item/component.rb +2 -2
  7. data/app/components/lookbook/params/field/component.rb +1 -1
  8. data/app/components/lookbook/tabs/component.html.erb +1 -1
  9. data/app/components/lookbook/tabs/component.js +4 -0
  10. data/app/views/layouts/lookbook/application.html.erb +52 -50
  11. data/app/views/layouts/lookbook/shell.html.erb +1 -0
  12. data/app/views/lookbook/inspector/inputs/_toggle.html.erb +3 -3
  13. data/lib/lookbook/entities/collections/concerns/hierarchical_collection.rb +0 -4
  14. data/lib/lookbook/entities/collections/entity_collection.rb +9 -14
  15. data/lib/lookbook/entities/collections/preview_collection.rb +8 -2
  16. data/lib/lookbook/entities/collections/preview_example_collection.rb +0 -5
  17. data/lib/lookbook/entities/concerns/locatable.rb +2 -2
  18. data/lib/lookbook/entities/concerns/navigable.rb +19 -3
  19. data/lib/lookbook/entities/entity.rb +5 -0
  20. data/lib/lookbook/entities/preview.rb +1 -1
  21. data/lib/lookbook/entities/preview_example.rb +10 -1
  22. data/lib/lookbook/services/data/resolvers/file_resolver.rb +1 -1
  23. data/lib/lookbook/support/tree_node.rb +10 -6
  24. data/lib/lookbook/tags/param_tag.rb +1 -1
  25. data/lib/lookbook/version.rb +1 -1
  26. data/public/lookbook-assets/js/lookbook.js +43 -42
  27. data/public/lookbook-assets/js/lookbook.js.map +1 -1
  28. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a8ca9a9db0798d392083b4470397bf94260811a1f82f8b89dee0e5646fca156
4
- data.tar.gz: 24fe83948823edd7387b11ca2ee5628f778a15034173491bfdfd20347d6b1484
3
+ metadata.gz: e489fa4bdff458098a029cf9d2bc25d6e16a70e11a92a1be7a77114ad43e0f63
4
+ data.tar.gz: c5efc75e6a4d0b16493cd1eb21d3ace790af22b64ba22e3c00edfb1bb6a58e5d
5
5
  SHA512:
6
- metadata.gz: 1463db9307bc67d9224a4a96f21ee404902fe0e266b40b0456c84e551a26b96a779e816f2780b5c1ea30189b8d94e3e5dfc16ab6d2f0b3df3a0e06d8f2705282
7
- data.tar.gz: ea867f97d2cb0d532e59c3c62de31405dca1fe29e7f9ade020fe6b7eb2cb3d2b04d16d7b110e3479eaa54316d6df9ba3328594c73c659e37f6c513867325ad54
6
+ metadata.gz: 9cf5f58aedde5c3bac838a15f9fc1dadabc46ce667987b689ce4fc9a83c95cd11fe908f1b2fb69f59b20ffdaa85a306e8e8af89988b65de085d73c5a7b73f9d8
7
+ data.tar.gz: 59d122a52a50a77a9e30cfd484789fa1de533ca244b20c7cecefd02521c30fd5c962d59c2d40ff85f1fff786a1d4a864c3f3887625dc08214b2dac96c4a22f10
@@ -12,7 +12,7 @@ module Lookbook
12
12
  end
13
13
 
14
14
  def items
15
- tree.map do |node|
15
+ @items ||= tree.map do |node|
16
16
  item_class = (node.type == :directory) ? Nav::Directory::Component : Nav::Entity::Component
17
17
  lookbook_render item_class.new node, nav_id: id
18
18
  end
@@ -1,10 +1,12 @@
1
1
  <%= render_component_tag :li,
2
2
  id: id,
3
+ key: "#{id}-directory",
3
4
  class: "list-none",
4
5
  "x-show": "!filteredOut",
5
6
  data: { "entity-type": :directory },
6
7
  cloak: true do %>
7
8
  <%= lookbook_tag :button,
9
+ key: "#{id}-action",
8
10
  class: "nav-action",
9
11
  style: "padding-left: #{left_pad}px",
10
12
  "x-bind": "bindings.toggle" do %>
@@ -1,11 +1,13 @@
1
1
  <%= render_component_tag :li,
2
2
  id: id,
3
+ key: "#{id}-entity-#{type}",
3
4
  class: "list-none",
4
5
  "x-show": "!filteredOut",
5
6
  data: { "entity-type": type },
6
7
  cloak: true do %>
7
8
  <%= lookbook_tag href.present? ? :a : :button,
8
9
  href: href,
10
+ key: "#{id}-action",
9
11
  class: "nav-action",
10
12
  style: "padding-left: #{left_pad}px",
11
13
  "x-bind": "bindings.#{href.present? ? "link" : "toggle"}" do %>
@@ -8,7 +8,7 @@ module Lookbook
8
8
  }.freeze
9
9
 
10
10
  def nav_icon
11
- ICONS[type] || :file
11
+ ICONS[collapsed? ? :preview : node.type] || :file
12
12
  end
13
13
 
14
14
  def href
@@ -15,11 +15,11 @@ module Lookbook
15
15
  end
16
16
 
17
17
  def left_pad
18
- ((depth - 1) * 12) + 24
18
+ depth * 12
19
19
  end
20
20
 
21
21
  def children
22
- @children ||= node.map { |node| render_item(node) }
22
+ @children ||= node.sort.map { |node| render_item(node) }
23
23
  end
24
24
 
25
25
  def nav_icon
@@ -34,7 +34,7 @@ module Lookbook
34
34
  value: param.value,
35
35
  value_type: param.value_type,
36
36
  value_default: param.value_default,
37
- input_options: input_options.except(:choices),
37
+ input_options: input_options.except(:choices, :opts),
38
38
  choices: input_options[:choices])
39
39
  end
40
40
 
@@ -13,7 +13,7 @@
13
13
  <%= lookbook_render :button, icon: :menu, class: "-ml-3", "x-show": "visibleTabsCount === 0" %>
14
14
  </div>
15
15
  <div class="hidden">
16
- <div x-ref="tabsDropdown" data-cloak>
16
+ <div x-ref="tabsDropdown" x-cloak>
17
17
  <%= safe_join(dropdown_tabs) %>
18
18
  </div>
19
19
  </div>
@@ -33,6 +33,10 @@ export default function tabsComponent(store) {
33
33
 
34
34
  init() {
35
35
  this.$nextTick(() => {
36
+ if (this.$root.parentElement.offsetWidth === this.$root.offsetWidth) {
37
+ this.visibleTabsCount = this.tabs.length;
38
+ }
39
+
36
40
  dropdown = tippy(this.$refs.dropdownTrigger, {
37
41
  content: this.$refs.tabsDropdown,
38
42
  theme: "menu",
@@ -1,60 +1,62 @@
1
1
  <% content_for :shell do %>
2
2
  <% if @previews.any? || @pages.any? %>
3
- <%= lookbook_render :split_layout,
4
- alpine_data: "$store.layout.main",
5
- ":class": "$store.layout.mobile && '!block'" do |layout| %>
3
+ <% cache do %>
4
+ <%= lookbook_render :split_layout,
5
+ alpine_data: "$store.layout.main",
6
+ ":class": "$store.layout.mobile && '!block'" do |layout| %>
6
7
 
7
- <% layout.pane id: "app-sidebar", class: "flex flex-col bg-lookbook-sidebar-bg relative translate-x-0",
8
- ":class": "{
9
- 'transition': $store.layout.mobile,
10
- 'translate-x-full': $store.layout.mobile && sidebarHidden,
11
- '!absolute right-0 bottom-0 top-[40px] h-[calc(100%_-_40px)] w-full max-w-[420px] z-50 border-l border-lookbook-divider': $store.layout.mobile
12
- }",
13
- "@click.outside": "closeMobileSidebar",
14
- cloak: true do %>
8
+ <% layout.pane id: "app-sidebar", class: "flex flex-col bg-lookbook-sidebar-bg relative translate-x-0",
9
+ ":class": "{
10
+ 'transition': $store.layout.mobile,
11
+ 'translate-x-full': $store.layout.mobile && sidebarHidden,
12
+ '!absolute right-0 bottom-0 top-[40px] h-[calc(100%_-_40px)] w-full max-w-[420px] z-50 border-l border-lookbook-divider': $store.layout.mobile
13
+ }",
14
+ "@click.outside": "closeMobileSidebar",
15
+ cloak: true do %>
15
16
 
16
- <%= lookbook_render :split_layout,
17
- alpine_data: "$store.layout.#{@pages.any? && @previews.any? ? "sidebar" : "singleSectionSidebar"}",
18
- style: "height: calc(100vh - 2.5rem);" do |layout| %>
17
+ <%= lookbook_render :split_layout,
18
+ alpine_data: "$store.layout.#{@pages.any? && @previews.any? ? "sidebar" : "singleSectionSidebar"}",
19
+ style: "height: calc(100vh - 2.5rem);" do |layout| %>
19
20
 
20
- <% if @previews.any? %>
21
- <% layout.pane class: "overflow-hidden" do %>
22
- <%= lookbook_render :nav,
23
- id: "previews-nav",
24
- tree: @previews.to_tree,
25
- alpine_data: "$store.nav.previews" do |nav| %>
26
- <%= nav.toolbar do |toolbar| %>
27
- <% toolbar.section padded: true do %>
28
- <h4 class="pt-1">Previews</h4>
29
- <% end %>
30
- <% toolbar.section align: :right, padded: false do %>
31
- <%= lookbook_render :button_group, size: :xs do |group| %>
32
- <% group.button icon: :minus_square,
33
- tooltip: "Collapse all",
34
- "@click": "closeAll" %>
21
+ <% if @previews.any? %>
22
+ <% layout.pane class: "overflow-hidden" do %>
23
+ <%= lookbook_render :nav,
24
+ id: "previews-nav",
25
+ tree: @previews.to_tree,
26
+ alpine_data: "$store.nav.previews" do |nav| %>
27
+ <%= nav.toolbar do |toolbar| %>
28
+ <% toolbar.section padded: true do %>
29
+ <h4 class="pt-1">Previews</h4>
30
+ <% end %>
31
+ <% toolbar.section align: :right, padded: false do %>
32
+ <%= lookbook_render :button_group, size: :xs do |group| %>
33
+ <% group.button icon: :minus_square,
34
+ tooltip: "Collapse all",
35
+ "@click": "closeAll" %>
36
+ <% end %>
35
37
  <% end %>
36
38
  <% end %>
39
+ <% nav.filter store: "$store.nav.previews.filter", placeholder: "Filter previews by name&hellip;" %>
37
40
  <% end %>
38
- <% nav.filter store: "$store.nav.previews.filter", placeholder: "Filter previews by name&hellip;" %>
39
41
  <% end %>
40
42
  <% end %>
41
- <% end %>
42
43
 
43
- <% if @pages.any? %>
44
- <% layout.pane class: "overflow-hidden" do %>
45
- <%= lookbook_render :nav,
46
- id: "pages-nav",
47
- tree: @pages.to_tree,
48
- alpine_data: "$store.nav.pages" do |nav| %>
49
- <%= nav.toolbar do |toolbar| %>
50
- <% toolbar.section padded: true do %>
51
- <h4 class="pt-1">Pages</h4>
52
- <% end %>
53
- <% toolbar.section align: :right, padded: false do %>
54
- <%= lookbook_render :button_group, size: :xs do |group| %>
55
- <% group.button icon: :minus_square,
56
- tooltip: "Collapse all",
57
- "@click": "closeAll" %>
44
+ <% if @pages.any? %>
45
+ <% layout.pane class: "overflow-hidden" do %>
46
+ <%= lookbook_render :nav,
47
+ id: "pages-nav",
48
+ tree: @pages.to_tree,
49
+ alpine_data: "$store.nav.pages" do |nav| %>
50
+ <%= nav.toolbar do |toolbar| %>
51
+ <% toolbar.section padded: true do %>
52
+ <h4 class="pt-1">Pages</h4>
53
+ <% end %>
54
+ <% toolbar.section align: :right, padded: false do %>
55
+ <%= lookbook_render :button_group, size: :xs do |group| %>
56
+ <% group.button icon: :minus_square,
57
+ tooltip: "Collapse all",
58
+ "@click": "closeAll" %>
59
+ <% end %>
58
60
  <% end %>
59
61
  <% end %>
60
62
  <% end %>
@@ -62,10 +64,10 @@
62
64
  <% end %>
63
65
  <% end %>
64
66
  <% end %>
65
- <% end %>
66
67
 
67
- <% layout.pane id: "app-main", class: "overflow-hidden h-full", ":class": "$store.layout.mobile && 'w-screen'" do %>
68
- <%= content_for?(:main) ? yield(:main) : yield %>
68
+ <% layout.pane id: "app-main", class: "overflow-hidden h-full", ":class": "$store.layout.mobile && 'w-screen'" do %>
69
+ <%= content_for?(:main) ? yield(:main) : yield %>
70
+ <% end %>
69
71
  <% end %>
70
72
  <% end %>
71
73
  <% else %>
@@ -76,4 +78,4 @@
76
78
  <div class="absolute opacity-0 bg-black inset-0 top-[39px] z-[-1] transition-opacity" :class="($store.layout.mobile && !sidebarHidden) && '!opacity-30 !z-40'" data-cloak></div>
77
79
  <% end %>
78
80
 
79
- <%= render template: "layouts/lookbook/shell" %>
81
+ <%= render template: "layouts/lookbook/shell" %>
@@ -2,6 +2,7 @@
2
2
  <div
3
3
  id="app"
4
4
  x-data="app"
5
+ x-cloak
5
6
  @popstate.window="handleNavigation"
6
7
  @click.document="hijax"
7
8
  @navigation:start="closeMobileSidebar"
@@ -11,10 +11,10 @@ span_classes = [
11
11
  ]
12
12
  %>
13
13
 
14
- <%= button_tag **input_options,
14
+ <%= tag.button **input_options,
15
15
  class: class_names(button_classes),
16
16
  role: "switch",
17
17
  type: "button",
18
- "@click.stop": "value = value == 'true' ? 'false' : 'true'" do %>
18
+ "@click.stop": "value = value == 'true' ? 'false' : 'true'", escape: false do %>
19
19
  <%= tag.span "aria-hidden": true, class: class_names(span_classes) %>
20
- <% end %>
20
+ <% end %>
@@ -18,10 +18,6 @@ module Lookbook
18
18
  entities.append(node.content? ? node.content : collect_ordered_entities(node))
19
19
  end.flatten
20
20
  end
21
-
22
- def sort_entities
23
- @entities.sort_by! { |entity| [entity.depth, entity.position, entity.label] }
24
- end
25
21
  end
26
22
  end
27
23
  end
@@ -12,53 +12,48 @@ module Lookbook
12
12
  add(entities)
13
13
  end
14
14
 
15
- def add(entities = nil)
16
- Array(entities).each do |entity|
15
+ def add(to_add = nil)
16
+ Array(to_add).each do |entity|
17
17
  unless find_by_path(entity.path)
18
- clear_cache
19
18
  @entities.push(entity)
20
19
  end
21
20
  end
22
- sort_entities
21
+ clear_cache
23
22
  end
24
23
 
25
24
  def find_by_id(id)
26
25
  id = Utils.id(id)
27
- find { |entity| entity.id == id }
26
+ entities.find { |entity| entity.id == id }
28
27
  end
29
28
 
30
29
  def find_by_path(path)
31
- find { |entity| entity.path.to_s == path.to_s }
30
+ entities.find { |entity| entity.path.to_s == path.to_s }
32
31
  end
33
32
 
34
33
  def next(entity)
35
- index = find_index { |i| i.path == entity.path }
34
+ index = entities.find_index { |i| i.path == entity.path }
36
35
  entities[index + 1] unless index.nil?
37
36
  end
38
37
 
39
38
  def previous(entity)
40
- index = find_index { |i| i.path == entity.path }
39
+ index = entities.find_index { |i| i.path == entity.path }
41
40
  entities[index - 1] if !index.nil? && index > 0
42
41
  end
43
42
 
44
43
  def each(&block)
45
44
  if block
46
- entities.each { |entity| yield entity }
45
+ entities.sort.each { |entity| yield entity }
47
46
  else
48
47
  to_enum(:each)
49
48
  end
50
49
  end
51
50
 
52
51
  def flat_map(...)
53
- map(...).map(&:to_a).flatten
52
+ entities.map(...).map(&:to_a).flatten
54
53
  end
55
54
 
56
55
  protected
57
56
 
58
- def sort_entities
59
- @entities.sort_by! { |entity| [entity.label] }
60
- end
61
-
62
57
  def clear_cache
63
58
  @_cache = {}
64
59
  end
@@ -20,12 +20,18 @@ module Lookbook
20
20
 
21
21
  def self.preview_from_code_object(code_object)
22
22
  klass = code_object.path.constantize
23
- Preview.new(code_object) if klass.ancestors.include?(ViewComponent::Preview)
23
+ Preview.new(code_object) if preview_class?(klass)
24
24
  rescue => exception
25
- Lookbook.logger.error LookbookError.new(exception)
25
+ Lookbook.logger.error exception.to_s
26
26
  nil
27
27
  end
28
28
 
29
+ def self.preview_class?(klass)
30
+ if klass.ancestors.include?(ViewComponent::Preview)
31
+ !klass.respond_to?(:abstract_class) || klass.abstract_class != true
32
+ end
33
+ end
34
+
29
35
  protected
30
36
 
31
37
  def examples
@@ -1,9 +1,4 @@
1
1
  module Lookbook
2
2
  class PreviewExampleCollection < EntityCollection
3
- protected
4
-
5
- def sort_entities
6
- @entities.sort_by!(&:label) if Lookbook.config.sort_examples
7
- end
8
3
  end
9
4
  end
@@ -65,8 +65,8 @@ module Lookbook
65
65
  def base_directory
66
66
  return @_base_directory if @_base_directory
67
67
 
68
- directories = [Rails.root, *Array(base_directories)].map(&:to_s).sort_by(&:length).reverse
69
- @_base_directory ||= directories.first { |dir| file_path.start_with?(dir) }
68
+ directories = Array(base_directories).map(&:to_s).sort_by { |path| path.split("/").size }.reverse
69
+ @_base_directory ||= directories.find { |dir| file_path.to_s.start_with?(dir) }
70
70
  end
71
71
  end
72
72
  end
@@ -12,16 +12,32 @@ module Lookbook
12
12
  end
13
13
 
14
14
  def position
15
- if @position_prefixes && respond_to?(:file_name)
16
- PositionPrefixParser.call(file_name).first || 10000
15
+ return @_position if @_position
16
+
17
+ pos = if @position_prefixes && respond_to?(:file_name)
18
+ PositionPrefixParser.call(file_name).first || default_position
17
19
  else
18
- fetch_config(:position, 10000)
20
+ fetch_config(:position, default_position)
19
21
  end
22
+
23
+ @_position ||= pos.to_i
20
24
  end
21
25
 
22
26
  def depth
23
27
  path.split("/").size
24
28
  end
29
+
30
+ def default_position
31
+ @default_position || 10000
32
+ end
33
+
34
+ def <=>(other)
35
+ if respond_to?(:sort_handler, true)
36
+ sort_handler(other)
37
+ else
38
+ [position, label] <=> [other.position, other.label]
39
+ end
40
+ end
25
41
  end
26
42
  end
27
43
  end
@@ -1,5 +1,6 @@
1
1
  module Lookbook
2
2
  class Entity
3
+ include Comparable
3
4
  include Lookbook::Engine.routes.url_helpers
4
5
 
5
6
  def initialize(lookup_path = nil)
@@ -36,6 +37,10 @@ module Lookbook
36
37
  @_type ||= self.class.name.demodulize.underscore.downcase.to_sym
37
38
  end
38
39
 
40
+ def <=>(other)
41
+ label <=> other.label
42
+ end
43
+
39
44
  alias_method :path, :lookup_path
40
45
  alias_method :logical_path, :lookup_path
41
46
 
@@ -81,7 +81,7 @@ module Lookbook
81
81
  def example_entities
82
82
  public_methods = preview_class.public_instance_methods(false)
83
83
  method_objects = code_object.meths.select { |m| public_methods.include?(m.name) }
84
- method_objects.map { |code_object| PreviewExample.new(code_object, self) }
84
+ method_objects.map.with_index { |code_object, i| PreviewExample.new(code_object, self, position: i) }
85
85
  end
86
86
  end
87
87
  end
@@ -8,9 +8,10 @@ module Lookbook
8
8
 
9
9
  attr_reader :preview
10
10
 
11
- def initialize(code_object, preview)
11
+ def initialize(code_object, preview, position: nil)
12
12
  @code_object = code_object
13
13
  @preview = preview
14
+ @default_position = position
14
15
  @lookup_path = "#{parent.lookup_path}/#{name}"
15
16
  end
16
17
 
@@ -65,6 +66,14 @@ module Lookbook
65
66
 
66
67
  protected
67
68
 
69
+ def sort_handler(other_entity)
70
+ if Lookbook.config.sort_examples
71
+ label <=> other_entity.label
72
+ else
73
+ [position, label] <=> [other_entity.position, other_entity.label]
74
+ end
75
+ end
76
+
68
77
  def format_source(source)
69
78
  source.sub(/^def \w+\s?(\([^)]+\))?/m, "").split("\n")[0..-2].join("\n")
70
79
  end
@@ -22,7 +22,7 @@ module Lookbook
22
22
  end
23
23
 
24
24
  def resolve_path(path, base_dir)
25
- path.start_with?(".") ? File.expand_path(path, base_dir) : Rails.root.join(path)
25
+ Pathname(path.start_with?(".") ? File.expand_path(path, base_dir) : Rails.root.join(path))
26
26
  end
27
27
  end
28
28
  end
@@ -1,6 +1,7 @@
1
1
  module Lookbook
2
2
  class TreeNode
3
3
  include Enumerable
4
+ include Comparable
4
5
 
5
6
  delegate_missing_to :content
6
7
 
@@ -40,7 +41,6 @@ module Lookbook
40
41
 
41
42
  def add_child(name, content = nil, position: 10000)
42
43
  children << TreeNode.new("#{path}/#{name}", content, position: position)
43
- sort_children
44
44
  end
45
45
 
46
46
  def has_child?(name)
@@ -57,7 +57,7 @@ module Lookbook
57
57
 
58
58
  def each(&block)
59
59
  if block
60
- children.each do |child|
60
+ children.sort.each do |child|
61
61
  yield child
62
62
  end
63
63
  else
@@ -65,6 +65,14 @@ module Lookbook
65
65
  end
66
66
  end
67
67
 
68
+ def <=>(other)
69
+ if content?
70
+ content <=> (other.content? ? other.content : other)
71
+ else
72
+ [position, label] <=> [other.position, other.label]
73
+ end
74
+ end
75
+
68
76
  protected
69
77
 
70
78
  def content_value(method_name, fallback = nil)
@@ -72,10 +80,6 @@ module Lookbook
72
80
  value || fallback
73
81
  end
74
82
 
75
- def sort_children
76
- @children.sort_by! { |child| [child.position, child.label] }
77
- end
78
-
79
83
  def segments
80
84
  path.split("/")
81
85
  end
@@ -1,7 +1,7 @@
1
1
  module Lookbook
2
2
  class ParamTag < YardTag
3
3
  VALUE_TYPE_MATCHER = /^(\[\s?([A-Z]{1}\w+)\s?\])/
4
- DESCRIPTION_MATCHER = /"(.*[^\\])"$/
4
+ DESCRIPTION_MATCHER = /(?<=\s|^)"(.*[^\\])"(?:\s|$)/
5
5
 
6
6
  supports_options
7
7
 
@@ -1,3 +1,3 @@
1
1
  module Lookbook
2
- VERSION = "1.4.0"
2
+ VERSION = "1.4.2"
3
3
  end