lookbook 1.5.5 → 2.0.0.beta.0

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 (198) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -31
  3. data/app/assets/lookbook/css/lookbook.css +9 -0
  4. data/app/assets/lookbook/css/themes/blue.css +7 -0
  5. data/app/assets/lookbook/css/themes/green.css +7 -0
  6. data/app/assets/lookbook/css/themes/indigo.css +7 -0
  7. data/app/assets/lookbook/css/themes/rose.css +7 -0
  8. data/app/assets/lookbook/css/themes/zinc.css +7 -0
  9. data/app/assets/lookbook/css/tooltip.css +9 -6
  10. data/app/assets/lookbook/img/lucide-sprite.svg +4960 -0
  11. data/app/assets/lookbook/js/app.js +22 -4
  12. data/app/assets/lookbook/js/helpers/dom.js +4 -7
  13. data/app/assets/lookbook/js/helpers/string.js +4 -11
  14. data/app/assets/lookbook/js/index.js +61 -0
  15. data/app/assets/lookbook/js/lib/lookbook.js +113 -0
  16. data/app/assets/lookbook/js/lib/tippy.js +1 -0
  17. data/app/assets/lookbook/js/lookbook-core.js +1 -0
  18. data/app/assets/lookbook/js/lookbook.js +2 -61
  19. data/app/components/lookbook/base_component.rb +3 -1
  20. data/app/components/lookbook/button/component.html.erb +13 -24
  21. data/app/components/lookbook/button/component.js +13 -3
  22. data/app/components/lookbook/button/component.rb +16 -25
  23. data/app/components/lookbook/code/component.rb +0 -2
  24. data/app/components/lookbook/copy_button/component.html.erb +5 -5
  25. data/app/components/lookbook/copy_button/component.rb +6 -3
  26. data/app/components/lookbook/debug_menu/component.html.erb +1 -0
  27. data/app/components/lookbook/debug_menu/component.rb +12 -1
  28. data/app/components/lookbook/display_options/editor/component.html.erb +1 -1
  29. data/app/components/lookbook/display_options/field/component.css +0 -26
  30. data/app/components/lookbook/display_options/field/component.html.erb +1 -1
  31. data/app/components/lookbook/embed/component.html.erb +6 -51
  32. data/app/components/lookbook/embed/component.rb +17 -16
  33. data/app/components/lookbook/embed/inspector/component.html.erb +102 -0
  34. data/app/components/lookbook/embed/inspector/component.js +46 -0
  35. data/app/components/lookbook/embed/inspector/component.rb +64 -0
  36. data/app/components/lookbook/embed_code_dropdown/component.css +12 -0
  37. data/app/components/lookbook/embed_code_dropdown/component.html.erb +19 -0
  38. data/app/components/lookbook/embed_code_dropdown/component.js +26 -0
  39. data/app/components/lookbook/embed_code_dropdown/component.rb +41 -0
  40. data/app/components/lookbook/header/component.html.erb +7 -6
  41. data/app/components/lookbook/header/component.rb +5 -1
  42. data/app/components/lookbook/icon/component.html.erb +1 -1
  43. data/app/components/lookbook/icon_button/component.html.erb +20 -0
  44. data/app/components/lookbook/icon_button/component.rb +46 -0
  45. data/app/components/lookbook/nav/component.html.erb +0 -1
  46. data/app/components/lookbook/nav/entity/component.rb +2 -2
  47. data/app/components/lookbook/nav/item/component.rb +1 -1
  48. data/app/components/lookbook/page_tabs/component.html.erb +2 -2
  49. data/app/components/lookbook/params/editor/component.rb +1 -0
  50. data/app/components/lookbook/prose/component.rb +1 -3
  51. data/app/components/lookbook/tabs/component.html.erb +2 -2
  52. data/app/components/lookbook/tabs/component.js +1 -1
  53. data/app/components/lookbook/tag_component.rb +2 -1
  54. data/app/components/lookbook/text_button/component.html.erb +26 -0
  55. data/app/components/lookbook/text_button/component.rb +42 -0
  56. data/app/components/lookbook/toolbar/component.html.erb +1 -1
  57. data/app/components/lookbook/viewport/component.rb +0 -4
  58. data/app/controllers/concerns/lookbook/targetable_concern.rb +26 -22
  59. data/app/controllers/concerns/lookbook/with_panels_concern.rb +30 -0
  60. data/app/controllers/concerns/lookbook/with_preview_controller_concern.rb +4 -3
  61. data/app/controllers/lookbook/application_controller.rb +9 -12
  62. data/app/controllers/lookbook/embeds_controller.rb +148 -0
  63. data/app/controllers/lookbook/inspector_controller.rb +3 -22
  64. data/app/controllers/lookbook/page_controller.rb +7 -6
  65. data/app/controllers/lookbook/pages_controller.rb +3 -4
  66. data/app/controllers/lookbook/preview_controller.rb +17 -0
  67. data/app/controllers/lookbook/previews_controller.rb +10 -30
  68. data/app/helpers/lookbook/application_helper.rb +3 -19
  69. data/app/views/layouts/lookbook/application.html.erb +85 -60
  70. data/app/views/layouts/lookbook/embed.html.erb +16 -0
  71. data/app/views/layouts/lookbook/shell.html.erb +1 -1
  72. data/app/views/layouts/lookbook/skeleton.html.erb +13 -8
  73. data/app/views/lookbook/404.html.erb +2 -2
  74. data/app/views/lookbook/embeds/show.html.erb +12 -0
  75. data/app/views/lookbook/inspector/panels/_notes.html.erb +1 -1
  76. data/app/views/lookbook/inspector/panels/_output.html.erb +3 -3
  77. data/app/views/lookbook/inspector/panels/_source.html.erb +6 -6
  78. data/app/views/lookbook/inspector/show.html.erb +130 -123
  79. data/app/views/lookbook/pages/show.html.erb +81 -34
  80. data/app/views/lookbook/partials/_iframe_content_scripts.html.erb +1 -0
  81. data/app/views/lookbook/partials/_user_styles.html.erb +5 -0
  82. data/app/views/lookbook/previews/group.html.erb +14 -0
  83. data/app/views/lookbook/previews/preview.html.erb +5 -0
  84. data/app/views/lookbook/previews/show.html.erb +1 -0
  85. data/config/app.yml +31 -16
  86. data/config/panels.yml +23 -25
  87. data/config/routes.rb +3 -1
  88. data/config/tags.yml +6 -2
  89. data/lib/lookbook/cable/cable.rb +53 -0
  90. data/lib/lookbook/engine.rb +105 -93
  91. data/lib/lookbook/entities/collections/entity_collection.rb +11 -6
  92. data/lib/lookbook/entities/collections/page_collection.rb +33 -8
  93. data/lib/lookbook/entities/collections/preview_collection.rb +42 -17
  94. data/lib/lookbook/entities/collections/render_target_collection.rb +4 -0
  95. data/lib/lookbook/entities/collections/scenario_collection.rb +4 -0
  96. data/lib/lookbook/entities/concerns/{annotatable.rb → annotatable_entity.rb} +7 -6
  97. data/lib/lookbook/entities/concerns/{inspectable.rb → inspectable_entity.rb} +2 -1
  98. data/lib/lookbook/entities/concerns/{locatable.rb → locatable_entity.rb} +8 -14
  99. data/lib/lookbook/entities/concerns/navigable_entity.rb +44 -0
  100. data/lib/lookbook/entities/entity.rb +7 -2
  101. data/lib/lookbook/entities/{page.rb → page_entity.rb} +10 -6
  102. data/lib/lookbook/entities/{page_section.rb → page_section_entity.rb} +1 -1
  103. data/lib/lookbook/entities/preview_entity.rb +99 -0
  104. data/lib/lookbook/entities/renderable_entity.rb +50 -0
  105. data/lib/lookbook/entities/rendered_scenario_entity.rb +53 -0
  106. data/lib/lookbook/entities/scenario_entity.rb +112 -0
  107. data/lib/lookbook/entities/scenario_group_entity.rb +53 -0
  108. data/lib/lookbook/error.rb +5 -5
  109. data/lib/lookbook/file_watcher.rb +19 -35
  110. data/lib/lookbook/helpers/class_names_helper.rb +28 -0
  111. data/lib/lookbook/helpers/page_helper.rb +18 -0
  112. data/{app/helpers/lookbook → lib/lookbook/helpers}/preview_helper.rb +3 -0
  113. data/lib/lookbook/helpers/ui_elements_helper.rb +115 -0
  114. data/lib/lookbook/preview.rb +79 -0
  115. data/lib/lookbook/preview_controller_actions.rb +50 -0
  116. data/lib/lookbook/preview_parser.rb +4 -2
  117. data/lib/lookbook/reloaders.rb +71 -0
  118. data/lib/lookbook/runtime_context.rb +49 -0
  119. data/lib/lookbook/services/data/resolvers/data_resolver.rb +4 -6
  120. data/lib/lookbook/services/entities/entity_tree_builder.rb +6 -6
  121. data/lib/lookbook/services/list_resolver.rb +35 -0
  122. data/lib/lookbook/services/markdown_renderer.rb +12 -2
  123. data/lib/lookbook/services/priority_prefix_parser.rb +16 -0
  124. data/lib/lookbook/services/urls/search_param_encoder.rb +16 -0
  125. data/lib/lookbook/services/urls/search_param_parser.rb +7 -6
  126. data/lib/lookbook/stores/config_store.rb +16 -16
  127. data/lib/lookbook/stores/input_store.rb +1 -3
  128. data/lib/lookbook/stores/panel_store.rb +28 -50
  129. data/lib/lookbook/support/deprecation.rb +5 -0
  130. data/lib/lookbook/support/errors/preview_template_error.rb +7 -0
  131. data/lib/lookbook/support/evented_file_update_checker.rb +69 -0
  132. data/lib/lookbook/support/null_websocket.rb +9 -0
  133. data/lib/lookbook/support/store.rb +9 -0
  134. data/lib/lookbook/support/tree_node.rb +7 -7
  135. data/lib/lookbook/support/utils/path_utils.rb +7 -1
  136. data/lib/lookbook/support/utils/utils.rb +8 -0
  137. data/lib/lookbook/tags/{position_tag.rb → priority_tag.rb} +4 -4
  138. data/lib/lookbook/tags/renders_tag.rb +4 -0
  139. data/lib/lookbook/tags/tag_provider.rb +3 -0
  140. data/lib/lookbook/tags/type_tag.rb +7 -0
  141. data/lib/lookbook/tags/yard_tag.rb +1 -2
  142. data/lib/lookbook/version.rb +1 -1
  143. data/lib/lookbook/websocket.rb +6 -53
  144. data/lib/lookbook.rb +179 -53
  145. data/public/lookbook-assets/css/lookbook.css +432 -376
  146. data/public/lookbook-assets/css/lookbook.css.map +1 -1
  147. data/public/lookbook-assets/css/themes/blue.css +7 -0
  148. data/public/lookbook-assets/css/themes/blue.css.map +1 -1
  149. data/public/lookbook-assets/css/themes/green.css +7 -0
  150. data/public/lookbook-assets/css/themes/green.css.map +1 -1
  151. data/public/lookbook-assets/css/themes/indigo.css +7 -0
  152. data/public/lookbook-assets/css/themes/indigo.css.map +1 -1
  153. data/public/lookbook-assets/css/themes/rose.css +7 -0
  154. data/public/lookbook-assets/css/themes/rose.css.map +1 -1
  155. data/public/lookbook-assets/css/themes/zinc.css +7 -0
  156. data/public/lookbook-assets/css/themes/zinc.css.map +1 -1
  157. data/public/lookbook-assets/img/lucide-sprite.svg +4960 -0
  158. data/public/lookbook-assets/js/embed.js +1363 -843
  159. data/public/lookbook-assets/js/embed.js.map +1 -1
  160. data/public/lookbook-assets/js/iframe.js +906 -0
  161. data/public/lookbook-assets/js/iframe.js.map +1 -0
  162. data/public/lookbook-assets/js/index.js +13567 -0
  163. data/public/lookbook-assets/js/index.js.map +1 -0
  164. data/public/lookbook-assets/js/lookbook-core.js +85 -0
  165. data/public/lookbook-assets/js/lookbook-core.js.map +1 -0
  166. data/public/lookbook-assets/js/lookbook.js +151 -12726
  167. data/public/lookbook-assets/js/lookbook.js.map +1 -1
  168. data/public/lookbook-assets/lookbook-esm.js +1427 -0
  169. data/public/lookbook-assets/lookbook-esm.js.map +1 -0
  170. data/public/lookbook-assets/lookbook-global.js +1427 -0
  171. data/public/lookbook-assets/lookbook-global.js.map +1 -0
  172. data/public/lookbook-assets/lookbook.js +1427 -0
  173. data/public/lookbook-assets/lookbook.js.map +1 -0
  174. metadata +85 -77
  175. data/app/components/lookbook/embed/component.js +0 -39
  176. data/app/helpers/lookbook/component_helper.rb +0 -84
  177. data/app/helpers/lookbook/output_helper.rb +0 -19
  178. data/app/helpers/lookbook/page_helper.rb +0 -34
  179. data/app/views/layouts/lookbook/inspector.html.erb +0 -7
  180. data/app/views/layouts/lookbook/page.html.erb +0 -53
  181. data/app/views/layouts/lookbook/standalone.html.erb +0 -5
  182. data/app/views/lookbook/preview.html.erb +0 -14
  183. data/lib/lookbook/entities/collections/component_collection.rb +0 -4
  184. data/lib/lookbook/entities/collections/preview_example_collection.rb +0 -4
  185. data/lib/lookbook/entities/component.rb +0 -31
  186. data/lib/lookbook/entities/concerns/navigable.rb +0 -43
  187. data/lib/lookbook/entities/preview.rb +0 -87
  188. data/lib/lookbook/entities/preview_example.rb +0 -104
  189. data/lib/lookbook/entities/preview_group.rb +0 -52
  190. data/lib/lookbook/preview_actions.rb +0 -43
  191. data/lib/lookbook/process.rb +0 -21
  192. data/lib/lookbook/rendered_example.rb +0 -37
  193. data/lib/lookbook/services/position_prefix_parser.rb +0 -16
  194. data/lib/lookbook/services/urls/search_param_builder.rb +0 -13
  195. data/lib/lookbook/tags/component_tag.rb +0 -13
  196. /data/app/assets/lookbook/js/{embed.js → iframe.js} +0 -0
  197. /data/{app/channels/lookbook → lib/lookbook/cable}/connection.rb +0 -0
  198. /data/{app/channels/lookbook → lib/lookbook/cable}/reload_channel.rb +0 -0
@@ -14,7 +14,7 @@ module Lookbook
14
14
 
15
15
  def add(to_add = nil)
16
16
  Array(to_add).each do |entity|
17
- unless find_by_path(entity.path)
17
+ unless find_by_path(entity.lookup_path)
18
18
  @entities.push(entity)
19
19
  end
20
20
  end
@@ -23,20 +23,20 @@ module Lookbook
23
23
 
24
24
  def find_by_id(id)
25
25
  id = Utils.id(id)
26
- entities.find { |entity| entity.id == id }
26
+ @entities.find { |entity| entity.id == id }
27
27
  end
28
28
 
29
29
  def find_by_path(path)
30
- entities.find { |entity| entity.path.to_s == path.to_s }
30
+ @entities.find { |entity| entity.lookup_path.to_s == path.to_s }
31
31
  end
32
32
 
33
33
  def next(entity)
34
- index = entities.find_index { |i| i.path == entity.path }
34
+ index = entities.find_index { |i| i.lookup_path == entity.lookup_path }
35
35
  entities[index + 1] unless index.nil?
36
36
  end
37
37
 
38
38
  def previous(entity)
39
- index = entities.find_index { |i| i.path == entity.path }
39
+ index = entities.find_index { |i| i.lookup_path == entity.lookup_path }
40
40
  entities[index - 1] if !index.nil? && index > 0
41
41
  end
42
42
 
@@ -49,7 +49,12 @@ module Lookbook
49
49
  end
50
50
 
51
51
  def flat_map(...)
52
- entities.map(...).map(&:to_a).flatten
52
+ entities.map(...).map { |e| e.respond_to?(:to_a) ? e.to_a : e }.flatten
53
+ end
54
+
55
+ def clear_all
56
+ @entities = []
57
+ clear_cache
53
58
  end
54
59
 
55
60
  protected
@@ -2,14 +2,33 @@ module Lookbook
2
2
  class PageCollection < EntityCollection
3
3
  include HierarchicalCollection
4
4
 
5
- def load(page_paths)
6
- @entities = []
7
- clear_cache
5
+ def load(page_paths, changes = nil)
6
+ file_paths = PageCollection.file_paths(page_paths)
7
+ reload_all(file_paths) # TODO: Fix incremental reloading
8
+ # changes.present? ? reload_changed(file_paths, changes) : reload_all(file_paths)
9
+ end
8
10
 
9
- file_paths = page_paths.flat_map do |dir|
10
- PathUtils.normalize_paths(Dir["#{dir}/**/*.html.*", "#{dir}/**/*.md.*"].sort)
11
- end
11
+ def reload_all(file_paths)
12
+ clear_all
13
+ add(pages_from_paths(file_paths))
14
+ end
15
+
16
+ def reload_changed(file_paths, changes)
17
+ modified = Array(changes[:modified])
18
+ removed = Array(changes[:removed]) + modified
19
+ added = Array(changes[:added]) + modified
20
+
21
+ remove_by_file_path(removed)
22
+ add(pages_from_paths(added))
23
+ end
12
24
 
25
+ def remove_by_file_path(paths)
26
+ paths = Array(paths).map(&:to_s)
27
+ @entities.reject! { |page| page.file_path.to_s.in?(paths) }
28
+ clear_cache
29
+ end
30
+
31
+ def pages_from_paths(file_paths)
13
32
  entities = file_paths.map { |path| PageCollection.entity(path) }
14
33
  pages, sections = entities.partition { |page| page.type == :page }
15
34
 
@@ -20,11 +39,17 @@ module Lookbook
20
39
  parent.add_section(section)
21
40
  end
22
41
 
23
- add(pages)
42
+ pages
43
+ end
44
+
45
+ def self.file_paths(directories)
46
+ directories.flat_map do |dir|
47
+ PathUtils.normalize_paths(Dir["#{dir}/**/*.html.*", "#{dir}/**/*.md.*"].sort)
48
+ end
24
49
  end
25
50
 
26
51
  def self.entity(file_path)
27
- File.basename(file_path).match?(%r{\[(.*?\w+)\]}) ? PageSection.new(file_path) : Page.new(file_path)
52
+ File.basename(file_path).match?(%r{\[(.*?\w+)\]}) ? PageSectionEntity.new(file_path) : PageEntity.new(file_path)
28
53
  end
29
54
  end
30
55
  end
@@ -2,40 +2,65 @@ module Lookbook
2
2
  class PreviewCollection < EntityCollection
3
3
  include HierarchicalCollection
4
4
 
5
- def find_example_by_path(lookup_path)
6
- examples.find_by_path(lookup_path)
5
+ def find_scenario_by_path(lookup_path)
6
+ scenarios.find_by_path(lookup_path)
7
7
  end
8
8
 
9
9
  def find_by_preview_class(klass)
10
10
  find { |preview| preview.preview_class.name == klass.to_s }
11
11
  end
12
12
 
13
- def load(code_objects)
14
- @entities = []
15
- clear_cache
13
+ def load(code_objects, changes = nil)
14
+ changes.present? ? reload_changed(code_objects, changes) : reload_all(code_objects)
15
+ end
16
16
 
17
- previews = Array(code_objects).map { |obj| PreviewCollection.preview_from_code_object(obj) }.compact
17
+ def reload_all(code_objects)
18
+ clear_all
19
+ previews = code_objects.map { |obj| PreviewCollection.preview_from_code_object(obj) }.compact
18
20
  add(previews)
19
21
  end
20
22
 
21
- def self.preview_from_code_object(code_object)
22
- klass = code_object.path.constantize
23
- Preview.new(code_object) if preview_class?(klass)
24
- rescue => exception
25
- Lookbook.logger.error exception.to_s
26
- nil
23
+ def reload_changed(code_objects, changes)
24
+ modified = Array(changes[:modified])
25
+ removed = Array(changes[:removed]) + modified
26
+ added = Array(changes[:added]) + modified
27
+
28
+ remove_by_file_path(removed)
29
+
30
+ previews = added.map do |path|
31
+ code_object = code_objects.find { |obj| obj if obj&.file.to_s == path.to_s }
32
+ PreviewCollection.preview_from_code_object(code_object) if code_object
33
+ end.compact
34
+
35
+ add(previews)
27
36
  end
28
37
 
29
- def self.preview_class?(klass)
30
- if klass.ancestors.include?(ViewComponent::Preview)
31
- !klass.respond_to?(:abstract_class) || klass.abstract_class != true
38
+ def remove_by_file_path(paths)
39
+ paths = Array(paths).map(&:to_s)
40
+ @entities.reject! { |preview| preview.file_path.to_s.in?(paths) }
41
+ clear_cache
42
+ end
43
+
44
+ class << self
45
+ def preview_from_code_object(code_object)
46
+ klass = code_object.path.constantize
47
+ PreviewEntity.new(code_object) if preview_class?(klass)
48
+ rescue => exception
49
+ Lookbook.logger.error exception.to_s
50
+ nil
51
+ end
52
+
53
+ def preview_class?(klass)
54
+ if (defined?(ViewComponent) && klass.ancestors.include?(ViewComponent::Preview)) || klass.ancestors.include?(Lookbook::Preview)
55
+ !klass.respond_to?(:abstract_class) || klass.abstract_class != true
56
+ end
32
57
  end
33
58
  end
34
59
 
35
60
  protected
36
61
 
37
- def examples
38
- @_cache[:examples] ||= PreviewExampleCollection.new(flat_map(&:examples))
62
+ def scenarios
63
+ @_cache[:scenarios] ||= ScenarioCollection.new(flat_map(&:scenarios))
39
64
  end
40
65
  end
41
66
  end
@@ -0,0 +1,4 @@
1
+ module Lookbook
2
+ class RenderTargetCollection < EntityCollection
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Lookbook
2
+ class ScenarioCollection < EntityCollection
3
+ end
4
+ end
@@ -1,5 +1,6 @@
1
1
  module Lookbook
2
- module Annotatable
2
+ # @api private
3
+ module AnnotatableEntity
3
4
  extend ActiveSupport::Concern
4
5
 
5
6
  included do
@@ -23,8 +24,8 @@ module Lookbook
23
24
 
24
25
  def fetch_config(key, fallback = nil, &block)
25
26
  value = case key.to_sym
26
- when :components
27
- components_config
27
+ when :renders
28
+ renders_config
28
29
  when :display_options
29
30
  display_options_config
30
31
  else
@@ -36,10 +37,10 @@ module Lookbook
36
37
 
37
38
  private
38
39
 
39
- def components_config
40
- return unless has_tag?(:component)
40
+ def renders_config
41
+ return unless has_tag?(:component) || has_tag?(:renders)
41
42
 
42
- Array(tags(:component)).map(&:value).compact
43
+ [*tags(:component), *tags(:renders)].map(&:value).compact
43
44
  end
44
45
 
45
46
  def display_options_config
@@ -1,5 +1,6 @@
1
1
  module Lookbook
2
- module Inspectable
2
+ # @api private
3
+ module InspectableEntity
3
4
  extend ActiveSupport::Concern
4
5
 
5
6
  included do
@@ -1,5 +1,6 @@
1
1
  module Lookbook
2
- module Locatable
2
+ # @api private
3
+ module LocatableEntity
3
4
  extend ActiveSupport::Concern
4
5
 
5
6
  included do
@@ -41,20 +42,13 @@ module Lookbook
41
42
  @_logical_path ||= PathUtils.to_path(directory, file_name_base)
42
43
  end
43
44
 
44
- def full_path
45
- Lookbook.logger.warn "The `full_path` method has been deprecated - use `file_path` instead. `full_path` will be removed in v2.0"
46
- file_path
47
- end
48
-
49
- def rel_path
50
- Lookbook.logger.warn "The `rel_path` method has been deprecated - use `relative_file_path` instead. `rel_path` will be removed in v2.0"
51
- relative_file_path
52
- end
45
+ alias_method :full_path, :file_path
46
+ alias_method :rel_path, :relative_file_path
47
+ alias_method :dir_path, :directory_path
53
48
 
54
- def dir_path
55
- Lookbook.logger.warn "The `dir_path` method has been deprecated - use `directory_path` instead. `dir_path` will be removed in v2.0"
56
- directory_path
57
- end
49
+ deprecate full_path: :file_path, deprecator: Deprecation
50
+ deprecate rel_path: :relative_file_path, deprecator: Deprecation
51
+ deprecate dir_path: :directory_path, deprecator: Deprecation
58
52
 
59
53
  protected
60
54
 
@@ -0,0 +1,44 @@
1
+ module Lookbook
2
+ # @api private
3
+ module NavigableEntity
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ def hidden?
8
+ fetch_config(:hidden, false)
9
+ end
10
+
11
+ def visible?
12
+ !hidden?
13
+ end
14
+
15
+ def priority
16
+ return @_priority if @_priority
17
+
18
+ pos = if @priority_prefixes && respond_to?(:file_name)
19
+ PriorityPrefixParser.call(file_name).first || fetch_config(:priority, default_priority)
20
+ else
21
+ fetch_config(:priority, default_priority)
22
+ end
23
+
24
+ @_priority ||= pos.to_i
25
+ end
26
+
27
+ def depth
28
+ lookup_path.split("/").size
29
+ end
30
+
31
+ def default_priority
32
+ @default_priority || 10000
33
+ end
34
+
35
+ def <=>(other)
36
+ if respond_to?(:sort_handler, true)
37
+ sort_handler(other)
38
+ else
39
+ [priority, label] <=> [other.priority, other.label]
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -1,7 +1,10 @@
1
1
  module Lookbook
2
+ # Base entity class
3
+ #
4
+ # @api private
2
5
  class Entity
3
6
  include Comparable
4
- include Lookbook::Engine.routes.url_helpers
7
+ send(:include, Lookbook::Engine.routes.url_helpers) # YARD parsing workaround: https://github.com/lsegal/yard/issues/546
5
8
 
6
9
  def initialize(lookup_path = nil)
7
10
  @lookup_path = lookup_path
@@ -34,7 +37,7 @@ module Lookbook
34
37
  end
35
38
 
36
39
  def type
37
- @_type ||= self.class.name.demodulize.underscore.downcase.to_sym
40
+ @_type ||= self.class.name.gsub("Entity", "").demodulize.underscore.downcase.to_sym
38
41
  end
39
42
 
40
43
  def <=>(other)
@@ -44,6 +47,8 @@ module Lookbook
44
47
  alias_method :path, :lookup_path
45
48
  alias_method :logical_path, :lookup_path
46
49
 
50
+ deprecate path: :lookup_path, deprecator: Deprecation
51
+
47
52
  protected
48
53
 
49
54
  def fetch_config(key, fallback = nil, &block)
@@ -1,7 +1,11 @@
1
1
  module Lookbook
2
- class Page < Entity
3
- include Locatable
4
- include Navigable
2
+ # Represents a documentation page
3
+ #
4
+ # @ignore methods
5
+ # @api public
6
+ class PageEntity < Entity
7
+ include LocatableEntity
8
+ include NavigableEntity
5
9
 
6
10
  attr_reader :content, :sections
7
11
 
@@ -10,7 +14,7 @@ module Lookbook
10
14
  @base_directories = Engine.page_paths
11
15
  @lookup_path = PathUtils.to_lookup_path(relative_file_path)
12
16
  @frontmatter, @content = FrontmatterExtractor.call(file_contents)
13
- @position_prefixes = true
17
+ @priority_prefixes = true
14
18
  @sections = []
15
19
  end
16
20
 
@@ -46,12 +50,12 @@ module Lookbook
46
50
  end
47
51
 
48
52
  def url_path
49
- lookbook_page_path(path)
53
+ lookbook_page_path(lookup_path)
50
54
  end
51
55
 
52
56
  def add_section(section)
53
57
  @sections << section
54
- @sections.sort_by! { |section| [section.position, section.label] }
58
+ @sections.sort_by! { |section| [section.priority, section.label] }
55
59
  end
56
60
 
57
61
  def method_missing(method_name, *args, &block)
@@ -1,5 +1,5 @@
1
1
  module Lookbook
2
- class PageSection < Page
2
+ class PageSectionEntity < PageEntity
3
3
  attr_accessor :parent
4
4
 
5
5
  def initialize(file_path)
@@ -0,0 +1,99 @@
1
+ module Lookbook
2
+ # Represents a preview class
3
+ #
4
+ # @ignore methods
5
+ # @api public
6
+ class PreviewEntity < Entity
7
+ include AnnotatableEntity
8
+ include LocatableEntity
9
+ include NavigableEntity
10
+
11
+ delegate :render_args, to: :preview_class
12
+
13
+ attr_reader :preview_class
14
+
15
+ def initialize(code_object)
16
+ @code_object = code_object
17
+ @preview_class = code_object.path.constantize
18
+ @file_path = Pathname(code_object.file)
19
+ @base_directories = Engine.preview_paths
20
+
21
+ cleaned_path = relative_file_path.to_s
22
+ .gsub(/\/(component_preview|preview)(\..*)$/, "")
23
+ .gsub(/(_component_preview|_preview)(\..*)$/, "")
24
+
25
+ @lookup_path = PathUtils.to_lookup_path(cleaned_path)
26
+ end
27
+
28
+ def scenarios
29
+ @_scenarios ||= ScenarioCollection.new(load_scenarios)
30
+ end
31
+
32
+ def scenario(scenario_name)
33
+ scenarios.find { |m| m.name == scenario_name.to_s }
34
+ end
35
+
36
+ def visible_scenarios
37
+ @_visible_scenarios ||= ScenarioCollection.new(scenarios.select(&:visible?))
38
+ end
39
+
40
+ def default_scenario
41
+ visible_scenarios.first
42
+ end
43
+
44
+ def render_targets
45
+ @_render_targets ||= RenderTargetCollection.new(scenarios.flat_map(&:render_targets).uniq(&:lookup_path))
46
+ end
47
+
48
+ def render_target
49
+ render_targets.first
50
+ end
51
+
52
+ def display_options
53
+ global_options = Lookbook.config.preview_display_options
54
+ global_options.deep_merge(fetch_config(:display_options, {}))
55
+ end
56
+
57
+ def layout
58
+ preview_class.instance_variable_get(:@layout)
59
+ end
60
+
61
+ def url_path
62
+ lookbook_inspect_path(lookup_path)
63
+ end
64
+
65
+ def preview_class_name
66
+ preview_class.name
67
+ end
68
+
69
+ def guess_render_targets
70
+ [preview_class.name.chomp("Preview").constantize&.name]
71
+ rescue
72
+ []
73
+ end
74
+
75
+ alias_method :components, :render_targets
76
+ alias_method :component, :render_target
77
+ alias_method :examples, :scenarios
78
+ alias_method :example, :scenario
79
+
80
+ deprecate examples: :scenarios, deprecator: Deprecation
81
+ deprecate example: :scenario, deprecator: Deprecation
82
+
83
+ protected
84
+
85
+ def load_scenarios
86
+ return scenario_entities unless code_object.groups.any?
87
+
88
+ scenario_entities.group_by(&:group).flat_map do |group_name, grouped_scenarios|
89
+ group_name.nil? ? grouped_scenarios : ScenarioGroupEntity.new(group_name.presence || label.pluralize, grouped_scenarios, self)
90
+ end
91
+ end
92
+
93
+ def scenario_entities
94
+ public_methods = preview_class.public_instance_methods(false)
95
+ method_objects = code_object.meths.select { |m| public_methods.include?(m.name) }
96
+ method_objects.map.with_index { |code_object, i| ScenarioEntity.new(code_object, self, priority: i) }
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,50 @@
1
+ module Lookbook
2
+ # Represents the component or view template partial
3
+ # that is being rendered in a preview.
4
+ #
5
+ # @ignore methods
6
+ # @api public
7
+ class RenderableEntity < Entity
8
+ include LocatableEntity
9
+
10
+ def initialize(identifier)
11
+ @identifier = identifier
12
+ @base_directories = Engine.component_paths
13
+ @file_path = PathUtils.determine_full_path(component? ? "#{name}.rb" : identifier, @base_directories)
14
+ unless @file_path && File.exist?(@file_path)
15
+ raise LookbookError, "The render target #{@identifier} was not found."
16
+ end
17
+ @lookup_path = PathUtils.to_lookup_path(relative_file_path)
18
+ end
19
+
20
+ def component_class
21
+ @identifier.constantize if component?
22
+ end
23
+
24
+ def name
25
+ component? ? component_class.name.underscore : @identifier
26
+ end
27
+
28
+ def template_file_path
29
+ component? ? Dir.glob("#{directory_path}/#{file_name(true)}.*.erb").first : file_path
30
+ end
31
+
32
+ def inline?
33
+ component? ? template_file_path.present? : false
34
+ end
35
+
36
+ def component?
37
+ @identifier.first.upcase == @identifier.first &&
38
+ !@identifier.include?(".") &&
39
+ !@identifier.include?("/")
40
+ end
41
+
42
+ def template?
43
+ !component?
44
+ end
45
+
46
+ def type
47
+ component? ? :component : :template
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,53 @@
1
+ module Lookbook
2
+ # Represents a **rendered** preview scenario
3
+ #
4
+ # @ignore methods
5
+ # @api public
6
+ class RenderedScenarioEntity
7
+ delegate_missing_to :scenario
8
+
9
+ attr_reader :scenario
10
+
11
+ def initialize(scenario, output, params)
12
+ @scenario = scenario
13
+ @params = params
14
+ @output = output
15
+ end
16
+
17
+ def source
18
+ has_custom_template? ? template_source(template) : scenario.source
19
+ end
20
+
21
+ def source_lang
22
+ has_custom_template? ? template_lang(template) : scenario.source_lang
23
+ end
24
+
25
+ def output
26
+ @_output ||= CodeBeautifier.call(@output)
27
+ end
28
+
29
+ protected
30
+
31
+ attr_reader :params
32
+
33
+ def render_args
34
+ @_render_args ||= preview.render_args(scenario.name, params: params)
35
+ end
36
+
37
+ def template
38
+ render_args[:template]
39
+ end
40
+
41
+ def view?
42
+ render_args[:type] == :view
43
+ end
44
+
45
+ def has_custom_template?
46
+ !template.in?(system_templates) && !custom_source? && !view?
47
+ end
48
+
49
+ def system_templates
50
+ ["view_components/preview", Lookbook.config.preview_template]
51
+ end
52
+ end
53
+ end