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.
- checksums.yaml +4 -4
- data/README.md +13 -31
- data/app/assets/lookbook/css/lookbook.css +9 -0
- data/app/assets/lookbook/css/themes/blue.css +7 -0
- data/app/assets/lookbook/css/themes/green.css +7 -0
- data/app/assets/lookbook/css/themes/indigo.css +7 -0
- data/app/assets/lookbook/css/themes/rose.css +7 -0
- data/app/assets/lookbook/css/themes/zinc.css +7 -0
- data/app/assets/lookbook/css/tooltip.css +9 -6
- data/app/assets/lookbook/img/lucide-sprite.svg +4960 -0
- data/app/assets/lookbook/js/app.js +22 -4
- data/app/assets/lookbook/js/helpers/dom.js +4 -7
- data/app/assets/lookbook/js/helpers/string.js +4 -11
- data/app/assets/lookbook/js/index.js +61 -0
- data/app/assets/lookbook/js/lib/lookbook.js +113 -0
- data/app/assets/lookbook/js/lib/tippy.js +1 -0
- data/app/assets/lookbook/js/lookbook-core.js +1 -0
- data/app/assets/lookbook/js/lookbook.js +2 -61
- data/app/components/lookbook/base_component.rb +3 -1
- data/app/components/lookbook/button/component.html.erb +13 -24
- data/app/components/lookbook/button/component.js +13 -3
- data/app/components/lookbook/button/component.rb +16 -25
- data/app/components/lookbook/code/component.rb +0 -2
- data/app/components/lookbook/copy_button/component.html.erb +5 -5
- data/app/components/lookbook/copy_button/component.rb +6 -3
- data/app/components/lookbook/debug_menu/component.html.erb +1 -0
- data/app/components/lookbook/debug_menu/component.rb +12 -1
- data/app/components/lookbook/display_options/editor/component.html.erb +1 -1
- data/app/components/lookbook/display_options/field/component.css +0 -26
- data/app/components/lookbook/display_options/field/component.html.erb +1 -1
- data/app/components/lookbook/embed/component.html.erb +6 -51
- data/app/components/lookbook/embed/component.rb +17 -16
- data/app/components/lookbook/embed/inspector/component.html.erb +102 -0
- data/app/components/lookbook/embed/inspector/component.js +46 -0
- data/app/components/lookbook/embed/inspector/component.rb +64 -0
- data/app/components/lookbook/embed_code_dropdown/component.css +12 -0
- data/app/components/lookbook/embed_code_dropdown/component.html.erb +19 -0
- data/app/components/lookbook/embed_code_dropdown/component.js +26 -0
- data/app/components/lookbook/embed_code_dropdown/component.rb +41 -0
- data/app/components/lookbook/header/component.html.erb +7 -6
- data/app/components/lookbook/header/component.rb +5 -1
- data/app/components/lookbook/icon/component.html.erb +1 -1
- data/app/components/lookbook/icon_button/component.html.erb +20 -0
- data/app/components/lookbook/icon_button/component.rb +46 -0
- data/app/components/lookbook/nav/component.html.erb +0 -1
- data/app/components/lookbook/nav/entity/component.rb +2 -2
- data/app/components/lookbook/nav/item/component.rb +1 -1
- data/app/components/lookbook/page_tabs/component.html.erb +2 -2
- data/app/components/lookbook/params/editor/component.rb +1 -0
- data/app/components/lookbook/prose/component.rb +1 -3
- data/app/components/lookbook/tabs/component.html.erb +2 -2
- data/app/components/lookbook/tabs/component.js +1 -1
- data/app/components/lookbook/tag_component.rb +2 -1
- data/app/components/lookbook/text_button/component.html.erb +26 -0
- data/app/components/lookbook/text_button/component.rb +42 -0
- data/app/components/lookbook/toolbar/component.html.erb +1 -1
- data/app/components/lookbook/viewport/component.rb +0 -4
- data/app/controllers/concerns/lookbook/targetable_concern.rb +26 -22
- data/app/controllers/concerns/lookbook/with_panels_concern.rb +30 -0
- data/app/controllers/concerns/lookbook/with_preview_controller_concern.rb +4 -3
- data/app/controllers/lookbook/application_controller.rb +9 -12
- data/app/controllers/lookbook/embeds_controller.rb +148 -0
- data/app/controllers/lookbook/inspector_controller.rb +3 -22
- data/app/controllers/lookbook/page_controller.rb +7 -6
- data/app/controllers/lookbook/pages_controller.rb +3 -4
- data/app/controllers/lookbook/preview_controller.rb +17 -0
- data/app/controllers/lookbook/previews_controller.rb +10 -30
- data/app/helpers/lookbook/application_helper.rb +3 -19
- data/app/views/layouts/lookbook/application.html.erb +85 -60
- data/app/views/layouts/lookbook/embed.html.erb +16 -0
- data/app/views/layouts/lookbook/shell.html.erb +1 -1
- data/app/views/layouts/lookbook/skeleton.html.erb +13 -8
- data/app/views/lookbook/404.html.erb +2 -2
- data/app/views/lookbook/embeds/show.html.erb +12 -0
- data/app/views/lookbook/inspector/panels/_notes.html.erb +1 -1
- data/app/views/lookbook/inspector/panels/_output.html.erb +3 -3
- data/app/views/lookbook/inspector/panels/_source.html.erb +6 -6
- data/app/views/lookbook/inspector/show.html.erb +130 -123
- data/app/views/lookbook/pages/show.html.erb +81 -34
- data/app/views/lookbook/partials/_iframe_content_scripts.html.erb +1 -0
- data/app/views/lookbook/partials/_user_styles.html.erb +5 -0
- data/app/views/lookbook/previews/group.html.erb +14 -0
- data/app/views/lookbook/previews/preview.html.erb +5 -0
- data/app/views/lookbook/previews/show.html.erb +1 -0
- data/config/app.yml +31 -16
- data/config/panels.yml +23 -25
- data/config/routes.rb +3 -1
- data/config/tags.yml +6 -2
- data/lib/lookbook/cable/cable.rb +53 -0
- data/lib/lookbook/engine.rb +105 -93
- data/lib/lookbook/entities/collections/entity_collection.rb +11 -6
- data/lib/lookbook/entities/collections/page_collection.rb +33 -8
- data/lib/lookbook/entities/collections/preview_collection.rb +42 -17
- data/lib/lookbook/entities/collections/render_target_collection.rb +4 -0
- data/lib/lookbook/entities/collections/scenario_collection.rb +4 -0
- data/lib/lookbook/entities/concerns/{annotatable.rb → annotatable_entity.rb} +7 -6
- data/lib/lookbook/entities/concerns/{inspectable.rb → inspectable_entity.rb} +2 -1
- data/lib/lookbook/entities/concerns/{locatable.rb → locatable_entity.rb} +8 -14
- data/lib/lookbook/entities/concerns/navigable_entity.rb +44 -0
- data/lib/lookbook/entities/entity.rb +7 -2
- data/lib/lookbook/entities/{page.rb → page_entity.rb} +10 -6
- data/lib/lookbook/entities/{page_section.rb → page_section_entity.rb} +1 -1
- data/lib/lookbook/entities/preview_entity.rb +99 -0
- data/lib/lookbook/entities/renderable_entity.rb +50 -0
- data/lib/lookbook/entities/rendered_scenario_entity.rb +53 -0
- data/lib/lookbook/entities/scenario_entity.rb +112 -0
- data/lib/lookbook/entities/scenario_group_entity.rb +53 -0
- data/lib/lookbook/error.rb +5 -5
- data/lib/lookbook/file_watcher.rb +19 -35
- data/lib/lookbook/helpers/class_names_helper.rb +28 -0
- data/lib/lookbook/helpers/page_helper.rb +18 -0
- data/{app/helpers/lookbook → lib/lookbook/helpers}/preview_helper.rb +3 -0
- data/lib/lookbook/helpers/ui_elements_helper.rb +115 -0
- data/lib/lookbook/preview.rb +79 -0
- data/lib/lookbook/preview_controller_actions.rb +50 -0
- data/lib/lookbook/preview_parser.rb +4 -2
- data/lib/lookbook/reloaders.rb +71 -0
- data/lib/lookbook/runtime_context.rb +49 -0
- data/lib/lookbook/services/data/resolvers/data_resolver.rb +4 -6
- data/lib/lookbook/services/entities/entity_tree_builder.rb +6 -6
- data/lib/lookbook/services/list_resolver.rb +35 -0
- data/lib/lookbook/services/markdown_renderer.rb +12 -2
- data/lib/lookbook/services/priority_prefix_parser.rb +16 -0
- data/lib/lookbook/services/urls/search_param_encoder.rb +16 -0
- data/lib/lookbook/services/urls/search_param_parser.rb +7 -6
- data/lib/lookbook/stores/config_store.rb +16 -16
- data/lib/lookbook/stores/input_store.rb +1 -3
- data/lib/lookbook/stores/panel_store.rb +28 -50
- data/lib/lookbook/support/deprecation.rb +5 -0
- data/lib/lookbook/support/errors/preview_template_error.rb +7 -0
- data/lib/lookbook/support/evented_file_update_checker.rb +69 -0
- data/lib/lookbook/support/null_websocket.rb +9 -0
- data/lib/lookbook/support/store.rb +9 -0
- data/lib/lookbook/support/tree_node.rb +7 -7
- data/lib/lookbook/support/utils/path_utils.rb +7 -1
- data/lib/lookbook/support/utils/utils.rb +8 -0
- data/lib/lookbook/tags/{position_tag.rb → priority_tag.rb} +4 -4
- data/lib/lookbook/tags/renders_tag.rb +4 -0
- data/lib/lookbook/tags/tag_provider.rb +3 -0
- data/lib/lookbook/tags/type_tag.rb +7 -0
- data/lib/lookbook/tags/yard_tag.rb +1 -2
- data/lib/lookbook/version.rb +1 -1
- data/lib/lookbook/websocket.rb +6 -53
- data/lib/lookbook.rb +179 -53
- data/public/lookbook-assets/css/lookbook.css +432 -376
- data/public/lookbook-assets/css/lookbook.css.map +1 -1
- data/public/lookbook-assets/css/themes/blue.css +7 -0
- data/public/lookbook-assets/css/themes/blue.css.map +1 -1
- data/public/lookbook-assets/css/themes/green.css +7 -0
- data/public/lookbook-assets/css/themes/green.css.map +1 -1
- data/public/lookbook-assets/css/themes/indigo.css +7 -0
- data/public/lookbook-assets/css/themes/indigo.css.map +1 -1
- data/public/lookbook-assets/css/themes/rose.css +7 -0
- data/public/lookbook-assets/css/themes/rose.css.map +1 -1
- data/public/lookbook-assets/css/themes/zinc.css +7 -0
- data/public/lookbook-assets/css/themes/zinc.css.map +1 -1
- data/public/lookbook-assets/img/lucide-sprite.svg +4960 -0
- data/public/lookbook-assets/js/embed.js +1363 -843
- data/public/lookbook-assets/js/embed.js.map +1 -1
- data/public/lookbook-assets/js/iframe.js +906 -0
- data/public/lookbook-assets/js/iframe.js.map +1 -0
- data/public/lookbook-assets/js/index.js +13567 -0
- data/public/lookbook-assets/js/index.js.map +1 -0
- data/public/lookbook-assets/js/lookbook-core.js +85 -0
- data/public/lookbook-assets/js/lookbook-core.js.map +1 -0
- data/public/lookbook-assets/js/lookbook.js +151 -12726
- data/public/lookbook-assets/js/lookbook.js.map +1 -1
- data/public/lookbook-assets/lookbook-esm.js +1427 -0
- data/public/lookbook-assets/lookbook-esm.js.map +1 -0
- data/public/lookbook-assets/lookbook-global.js +1427 -0
- data/public/lookbook-assets/lookbook-global.js.map +1 -0
- data/public/lookbook-assets/lookbook.js +1427 -0
- data/public/lookbook-assets/lookbook.js.map +1 -0
- metadata +85 -77
- data/app/components/lookbook/embed/component.js +0 -39
- data/app/helpers/lookbook/component_helper.rb +0 -84
- data/app/helpers/lookbook/output_helper.rb +0 -19
- data/app/helpers/lookbook/page_helper.rb +0 -34
- data/app/views/layouts/lookbook/inspector.html.erb +0 -7
- data/app/views/layouts/lookbook/page.html.erb +0 -53
- data/app/views/layouts/lookbook/standalone.html.erb +0 -5
- data/app/views/lookbook/preview.html.erb +0 -14
- data/lib/lookbook/entities/collections/component_collection.rb +0 -4
- data/lib/lookbook/entities/collections/preview_example_collection.rb +0 -4
- data/lib/lookbook/entities/component.rb +0 -31
- data/lib/lookbook/entities/concerns/navigable.rb +0 -43
- data/lib/lookbook/entities/preview.rb +0 -87
- data/lib/lookbook/entities/preview_example.rb +0 -104
- data/lib/lookbook/entities/preview_group.rb +0 -52
- data/lib/lookbook/preview_actions.rb +0 -43
- data/lib/lookbook/process.rb +0 -21
- data/lib/lookbook/rendered_example.rb +0 -37
- data/lib/lookbook/services/position_prefix_parser.rb +0 -16
- data/lib/lookbook/services/urls/search_param_builder.rb +0 -13
- data/lib/lookbook/tags/component_tag.rb +0 -13
- /data/app/assets/lookbook/js/{embed.js → iframe.js} +0 -0
- /data/{app/channels/lookbook → lib/lookbook/cable}/connection.rb +0 -0
- /data/{app/channels/lookbook → lib/lookbook/cable}/reload_channel.rb +0 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
module Lookbook
|
|
2
|
+
# Represents a preview scenario method within a preview class
|
|
3
|
+
#
|
|
4
|
+
# @ignore methods
|
|
5
|
+
# @api public
|
|
6
|
+
class ScenarioEntity < Entity
|
|
7
|
+
include InspectableEntity
|
|
8
|
+
include AnnotatableEntity
|
|
9
|
+
include NavigableEntity
|
|
10
|
+
|
|
11
|
+
delegate :group, to: :code_object
|
|
12
|
+
|
|
13
|
+
attr_reader :preview
|
|
14
|
+
|
|
15
|
+
def initialize(code_object, preview, priority: nil)
|
|
16
|
+
@code_object = code_object
|
|
17
|
+
@preview = preview
|
|
18
|
+
@default_priority = priority
|
|
19
|
+
@lookup_path = "#{parent.lookup_path}/#{name}"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def id
|
|
23
|
+
@_id ||= Utils.id(fetch_config(:id) { "#{parent.id}-#{code_object.name}" })
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def name
|
|
27
|
+
@_name ||= Utils.name(code_object.name)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def display_options
|
|
31
|
+
parent.display_options.merge(fetch_config(:display_options, {}))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def render_targets
|
|
35
|
+
@_render_targets ||= RenderTargetCollection.new(load_render_targets)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def render_target
|
|
39
|
+
render_targets.first
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def scenarios
|
|
43
|
+
[self]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def template_source(template_path)
|
|
47
|
+
source_path = template_file_path(template_path)
|
|
48
|
+
source_path ? File.read(source_path) : nil
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def template_lang(template_path)
|
|
52
|
+
path = template_file_path(template_path)
|
|
53
|
+
Lookbook::Lang.guess(path) || Lookbook::Lang.find(:html)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def search_terms
|
|
57
|
+
[parent.label, label]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def url_path
|
|
61
|
+
lookbook_inspect_path(lookup_path)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def type
|
|
65
|
+
:scenario
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
alias_method :parent, :preview
|
|
69
|
+
alias_method :components, :render_targets
|
|
70
|
+
alias_method :component, :render_target
|
|
71
|
+
alias_method :lang, :source_lang
|
|
72
|
+
alias_method :examples, :scenarios
|
|
73
|
+
|
|
74
|
+
deprecate lang: :source_lang, deprecator: Deprecation
|
|
75
|
+
deprecate examples: :scenarios, deprecator: Deprecation
|
|
76
|
+
|
|
77
|
+
protected
|
|
78
|
+
|
|
79
|
+
def sort_handler(other_entity)
|
|
80
|
+
if Lookbook.config.preview_sort_scenarios
|
|
81
|
+
label <=> other_entity.label
|
|
82
|
+
else
|
|
83
|
+
[priority, label] <=> [other_entity.priority, other_entity.label]
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def format_source(source)
|
|
88
|
+
source.sub(/^def \w+\s?(\([^)]+\))?/m, "").split("\n")[0..-2].join("\n")
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def template_file_path(template_path)
|
|
92
|
+
return full_template_path(template_path) if respond_to?(:full_template_path, true)
|
|
93
|
+
|
|
94
|
+
search_dirs = [*Engine.preview_paths, *Engine.view_paths]
|
|
95
|
+
template_path = "#{template_path.to_s.sub(/\..*$/, "")}.html.*"
|
|
96
|
+
PathUtils.determine_full_path(template_path, search_dirs)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def load_render_targets
|
|
100
|
+
render_target_identifiers = [*fetch_config(:renders, []), *preview.send(:fetch_config, :renders, [])]
|
|
101
|
+
render_target_identifiers = preview.guess_render_targets if render_target_identifiers.empty?
|
|
102
|
+
|
|
103
|
+
render_targets = render_target_identifiers.map do |render_target|
|
|
104
|
+
RenderableEntity.new(render_target)
|
|
105
|
+
rescue NameError
|
|
106
|
+
Lookbook.logger.warn "#{render_target} was not found"
|
|
107
|
+
nil
|
|
108
|
+
end
|
|
109
|
+
render_targets.compact.uniq(&:lookup_path)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module Lookbook
|
|
2
|
+
# Represents a group of preview scenarios within a preview class
|
|
3
|
+
#
|
|
4
|
+
# @ignore methods
|
|
5
|
+
# @api public
|
|
6
|
+
class ScenarioGroupEntity < Entity
|
|
7
|
+
include NavigableEntity
|
|
8
|
+
|
|
9
|
+
attr_reader :scenarios, :preview
|
|
10
|
+
|
|
11
|
+
def initialize(name, scenarios, preview)
|
|
12
|
+
@name = Utils.name(name)
|
|
13
|
+
@scenarios = ScenarioCollection.new(scenarios)
|
|
14
|
+
@preview = preview
|
|
15
|
+
@lookup_path = "#{parent.lookup_path}/#{@name}"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def display_options
|
|
19
|
+
merged = {}
|
|
20
|
+
scenarios.to_a.reverse.map do |scenario|
|
|
21
|
+
merged.merge!(scenario.display_options)
|
|
22
|
+
end
|
|
23
|
+
merged
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def render_targets
|
|
27
|
+
@_render_targets ||= RenderTargetCollection.new(scenarios.flat_map(&:render_targets).uniq(&:path))
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def search_terms
|
|
31
|
+
[parent.label, label]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def tags(tag_name = nil)
|
|
35
|
+
scenarios.flat_map { |scenario| scenario.tags(tag_name) }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def tag(tag_name = nil)
|
|
39
|
+
tags(tag_name).first
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def url_path
|
|
43
|
+
lookbook_inspect_path(lookup_path)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def type
|
|
47
|
+
:group
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
alias_method :parent, :preview
|
|
51
|
+
alias_method :components, :render_targets
|
|
52
|
+
end
|
|
53
|
+
end
|
data/lib/lookbook/error.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module Lookbook
|
|
2
2
|
class Error < StandardError
|
|
3
|
-
delegate :full_message, :backtrace, :to_s, to: :
|
|
3
|
+
delegate :full_message, :backtrace, :to_s, to: :original
|
|
4
4
|
|
|
5
5
|
LINES_AROUND = 3
|
|
6
6
|
|
|
@@ -59,11 +59,11 @@ module Lookbook
|
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
def title
|
|
62
|
-
@title ||
|
|
62
|
+
@title || original.class.to_s
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
def message
|
|
66
|
-
(@message ||
|
|
66
|
+
(@message || original.message).gsub("(<unknown>):", "").strip.upcase_first
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
def file_name
|
|
@@ -80,7 +80,7 @@ module Lookbook
|
|
|
80
80
|
else
|
|
81
81
|
@file_path.presence || nil
|
|
82
82
|
end
|
|
83
|
-
path
|
|
83
|
+
path.nil? ? nil : path.to_s.delete_prefix("#{Rails.root}/")
|
|
84
84
|
end
|
|
85
85
|
|
|
86
86
|
def line_number
|
|
@@ -101,7 +101,7 @@ module Lookbook
|
|
|
101
101
|
|
|
102
102
|
protected
|
|
103
103
|
|
|
104
|
-
def
|
|
104
|
+
def original
|
|
105
105
|
@original.presence || self
|
|
106
106
|
end
|
|
107
107
|
|
|
@@ -1,46 +1,30 @@
|
|
|
1
1
|
module Lookbook
|
|
2
2
|
class FileWatcher
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if paths.any?
|
|
14
|
-
opts = opts.to_h
|
|
15
|
-
opts[:only] = /\.(#{Array(extensions).join("|")})$/
|
|
16
|
-
|
|
17
|
-
listeners << init_listener(paths, opts, &block)
|
|
3
|
+
class << self
|
|
4
|
+
def new(...)
|
|
5
|
+
if evented?
|
|
6
|
+
Lookbook.logger.debug "Using `EventedFileUpdateChecker` for file watching"
|
|
7
|
+
else
|
|
8
|
+
Lookbook.logger.debug "The 'listen' gem was not found. Using `FileUpdateChecker` for file watching"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
file_watcher.new(...)
|
|
18
12
|
end
|
|
19
|
-
end
|
|
20
13
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
Lookbook.logger.debug "Starting listeners"
|
|
24
|
-
listeners.each { |l| l.start }
|
|
14
|
+
def evented?
|
|
15
|
+
!(file_watcher <= ActiveSupport::FileUpdateChecker)
|
|
25
16
|
end
|
|
26
|
-
end
|
|
27
17
|
|
|
28
|
-
|
|
29
|
-
if listeners.any?
|
|
30
|
-
Lookbook.logger.debug "Stopping listeners"
|
|
31
|
-
listeners.each { |l| l.stop }
|
|
32
|
-
end
|
|
33
|
-
end
|
|
18
|
+
protected
|
|
34
19
|
|
|
35
|
-
|
|
20
|
+
def file_watcher
|
|
21
|
+
@_file_watcher ||= begin
|
|
22
|
+
require_relative "./support/evented_file_update_checker"
|
|
36
23
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
force_polling: force_polling
|
|
42
|
-
) do |modified, added, removed|
|
|
43
|
-
block.call({modified: modified, added: added, removed: removed})
|
|
24
|
+
EventedFileUpdateChecker
|
|
25
|
+
rescue LoadError
|
|
26
|
+
ActiveSupport::FileUpdateChecker
|
|
27
|
+
end
|
|
44
28
|
end
|
|
45
29
|
end
|
|
46
30
|
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Lookbook
|
|
2
|
+
module ClassNamesHelper
|
|
3
|
+
def build_tag_values(*args)
|
|
4
|
+
tag_values = []
|
|
5
|
+
|
|
6
|
+
args.each do |tag_value|
|
|
7
|
+
case tag_value
|
|
8
|
+
when Hash
|
|
9
|
+
tag_value.each do |key, val|
|
|
10
|
+
tag_values << key.to_s if val && key.present?
|
|
11
|
+
end
|
|
12
|
+
when Array
|
|
13
|
+
tag_values.concat build_tag_values(*tag_value)
|
|
14
|
+
else
|
|
15
|
+
tag_values << tag_value.to_s if tag_value.present?
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
tag_values
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def class_names(*args)
|
|
23
|
+
tokens = build_tag_values(*args).flat_map { |value| value.to_s.split(/\s+/) }.uniq
|
|
24
|
+
|
|
25
|
+
safe_join(tokens, " ")
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Lookbook
|
|
2
|
+
# Helpers for documentation page templates
|
|
3
|
+
#
|
|
4
|
+
# @api public
|
|
5
|
+
module PageHelper
|
|
6
|
+
# Returns the URL path to a page.
|
|
7
|
+
#
|
|
8
|
+
# @param id [String, PageEntity] The id or PageEntity instance to generate a URL path for
|
|
9
|
+
def page_path(id)
|
|
10
|
+
page = id.is_a?(PageEntity) ? id : Engine.pages.find_by_id(id)
|
|
11
|
+
if page.present?
|
|
12
|
+
lookbook_page_path page.lookup_path
|
|
13
|
+
else
|
|
14
|
+
Lookbook.logger.warn "Could not find page with id ':#{id}'"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
module Lookbook
|
|
2
|
+
# Helpers for rendering UI elements.
|
|
3
|
+
#
|
|
4
|
+
# These are available for use in documentation page templates
|
|
5
|
+
# and custom preview inspector panel templates.
|
|
6
|
+
#
|
|
7
|
+
# @api public
|
|
8
|
+
module UiElementsHelper
|
|
9
|
+
# Render an icon.
|
|
10
|
+
#
|
|
11
|
+
# Lookbook uses icons from the [Lucide Icons](https://lucide.dev/) set and
|
|
12
|
+
# a full list of available icon names can be found on that site.
|
|
13
|
+
#
|
|
14
|
+
# @example
|
|
15
|
+
# <%= icon :trash %>
|
|
16
|
+
# <%= icon :camera, size: 6, style: "color: red;" %>
|
|
17
|
+
#
|
|
18
|
+
# @param name [Symbol, String] Name of the icon
|
|
19
|
+
# @param opts [Hash] Options hash
|
|
20
|
+
def icon(name, **opts)
|
|
21
|
+
lookbook_render :icon, name: name, **opts
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Display a syntax-highlighted block of code.
|
|
25
|
+
#
|
|
26
|
+
# An alternative to using markdown code blocks for templates that have
|
|
27
|
+
# markdown parsing disabled, or for when more control is required.
|
|
28
|
+
#
|
|
29
|
+
# @param language [Symbol] Which language the code is written in
|
|
30
|
+
# @param opts [Hash] Options hash
|
|
31
|
+
# @param block [Proc] Code block
|
|
32
|
+
def code(language = :html, **opts, &block)
|
|
33
|
+
opts[:language] ||= language
|
|
34
|
+
lookbook_render :code, **opts, &block
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Render a 'live' embed of a component preview.
|
|
38
|
+
#
|
|
39
|
+
# If no scenario name is provided then the default (first) preview
|
|
40
|
+
# scenario will be rendered in the embed.
|
|
41
|
+
#
|
|
42
|
+
# @param preview [String] Name of the preview class to embed
|
|
43
|
+
# @param scenario [String] Example method name
|
|
44
|
+
# @param opts [Hash] Options hash
|
|
45
|
+
def embed(preview, scenario = nil, **opts)
|
|
46
|
+
preview_entity = if preview.is_a?(Symbol)
|
|
47
|
+
Engine.previews.find_by_path(preview)
|
|
48
|
+
else
|
|
49
|
+
Engine.previews.find_by_preview_class(preview)
|
|
50
|
+
end
|
|
51
|
+
scenario_entity = scenario ? preview_entity&.scenario(scenario) : preview_entity&.default_scenario
|
|
52
|
+
opts[:actions] ||= ["inspect", "open"]
|
|
53
|
+
|
|
54
|
+
lookbook_render Embed::Component.new(
|
|
55
|
+
scenario: scenario_entity,
|
|
56
|
+
params: opts.fetch(:params, {}),
|
|
57
|
+
options: opts.except(:params)
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @api private
|
|
62
|
+
def prose(**opts, &block)
|
|
63
|
+
lookbook_render :prose, **opts, &block
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# @api private
|
|
67
|
+
def lookbook_tag(tag = :div, **attrs, &block)
|
|
68
|
+
lookbook_render :tag, tag: tag, **attrs, &block
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# @api private
|
|
72
|
+
def lookbook_render(ref, **attrs, &block)
|
|
73
|
+
comp = if ref.is_a? ViewComponent::Base
|
|
74
|
+
ref
|
|
75
|
+
else
|
|
76
|
+
klass = component_class(ref)
|
|
77
|
+
attrs.key?(:content) ? klass.new(**attrs.except(:content)).with_content(attrs[:content]) : klass.new(**attrs)
|
|
78
|
+
end
|
|
79
|
+
if block && !attrs.key?(:content)
|
|
80
|
+
public_send render_method_name, comp, &block
|
|
81
|
+
else
|
|
82
|
+
public_send render_method_name, comp
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
private
|
|
87
|
+
|
|
88
|
+
COMPONENT_CLASSES = {} # cache for constantized references
|
|
89
|
+
|
|
90
|
+
# @api private
|
|
91
|
+
def render_method_name
|
|
92
|
+
if Rails.application.config.view_component.render_monkey_patch_enabled || Rails.version.to_f >= 6.1
|
|
93
|
+
:render
|
|
94
|
+
else
|
|
95
|
+
:render_component
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# @api private
|
|
100
|
+
def component_class(ref)
|
|
101
|
+
klass = COMPONENT_CLASSES[ref]
|
|
102
|
+
if klass.nil?
|
|
103
|
+
ref = ref.to_s.tr("-", "_")
|
|
104
|
+
class_namespace = ref.camelize
|
|
105
|
+
begin
|
|
106
|
+
klass = "Lookbook::#{class_namespace}::Component".constantize
|
|
107
|
+
rescue
|
|
108
|
+
klass = "Lookbook::#{class_namespace}Component".constantize
|
|
109
|
+
end
|
|
110
|
+
COMPONENT_CLASSES[ref] = klass
|
|
111
|
+
end
|
|
112
|
+
klass
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
module Lookbook
|
|
2
|
+
class Preview
|
|
3
|
+
include ActionView::Helpers::TagHelper
|
|
4
|
+
include ActionView::Helpers::AssetTagHelper
|
|
5
|
+
|
|
6
|
+
def render(component = nil, **args, &block)
|
|
7
|
+
if component.nil?
|
|
8
|
+
{
|
|
9
|
+
type: :view,
|
|
10
|
+
template: args[:template] || Lookbook.config.preview_template,
|
|
11
|
+
args: args,
|
|
12
|
+
locals: args[:locals] || {},
|
|
13
|
+
block: block
|
|
14
|
+
}
|
|
15
|
+
else
|
|
16
|
+
{
|
|
17
|
+
type: component.is_a?(String) ? :view : :component,
|
|
18
|
+
args: args,
|
|
19
|
+
block: block,
|
|
20
|
+
component: component,
|
|
21
|
+
locals: {},
|
|
22
|
+
template: Lookbook.config.preview_template
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def render_with_template(template: nil, locals: nil)
|
|
28
|
+
{
|
|
29
|
+
type: :template,
|
|
30
|
+
template: template,
|
|
31
|
+
locals: locals.to_h
|
|
32
|
+
}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
alias_method :render_component, :render
|
|
36
|
+
|
|
37
|
+
class << self
|
|
38
|
+
# Returns the arguments for rendering of the component in its layout
|
|
39
|
+
def render_args(scenario, params: {})
|
|
40
|
+
scenario_params_names = instance_method(scenario).parameters.map(&:last)
|
|
41
|
+
provided_params = params.slice(*scenario_params_names).to_h.symbolize_keys
|
|
42
|
+
result = provided_params.empty? ? new.public_send(scenario) : new.public_send(scenario, **provided_params)
|
|
43
|
+
result ||= {}
|
|
44
|
+
result[:template] = scenario_template_path(scenario) if result[:template].nil?
|
|
45
|
+
@layout = nil unless defined?(@layout)
|
|
46
|
+
result.merge(layout: @layout)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# rubocop:disable Style/TrivialAccessors
|
|
50
|
+
def layout(layout_name)
|
|
51
|
+
@layout = layout_name
|
|
52
|
+
end
|
|
53
|
+
# rubocop:enable Style/TrivialAccessors
|
|
54
|
+
|
|
55
|
+
# Returns the relative path (from preview_path) to the scenario template if the template exists
|
|
56
|
+
def scenario_template_path(scenario)
|
|
57
|
+
preview_name = name.chomp("Preview").underscore
|
|
58
|
+
preview_path =
|
|
59
|
+
Engine.preview_paths.detect do |path|
|
|
60
|
+
Dir["#{path}/#{preview_name}_preview/#{scenario}.html.*"].first
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
if preview_path.nil?
|
|
64
|
+
raise(
|
|
65
|
+
PreviewTemplateError,
|
|
66
|
+
"A preview template for scenario #{scenario} doesn't exist.\n\n" \
|
|
67
|
+
"To fix this issue, create a template for the scenario."
|
|
68
|
+
)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
path = Dir["#{preview_path}/#{preview_name}_preview/#{scenario}.html.*"].first
|
|
72
|
+
Pathname.new(path)
|
|
73
|
+
.relative_path_from(Pathname.new(preview_path))
|
|
74
|
+
.to_s
|
|
75
|
+
.sub(/\..*$/, "")
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module Lookbook
|
|
2
|
+
module PreviewControllerActions
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
helper PreviewHelper
|
|
7
|
+
prepend_view_path Engine.root.join("app/views")
|
|
8
|
+
before_action :permit_embeds
|
|
9
|
+
|
|
10
|
+
def render_scenario_to_string(preview, scenario_name)
|
|
11
|
+
prepend_application_view_paths
|
|
12
|
+
prepend_preview_examples_view_path
|
|
13
|
+
|
|
14
|
+
@preview = preview
|
|
15
|
+
@scenario_name = scenario_name
|
|
16
|
+
@render_args = @preview.render_args(@scenario_name, params: params.permit!)
|
|
17
|
+
template = @render_args[:template]
|
|
18
|
+
locals = @render_args[:locals]
|
|
19
|
+
opts = {}
|
|
20
|
+
opts[:layout] = nil
|
|
21
|
+
opts[:locals] = locals if locals.present?
|
|
22
|
+
|
|
23
|
+
with_optional_action_view_annotations do
|
|
24
|
+
render html: render_to_string(template, **opts)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def render_in_layout_to_string(template, locals, opts = {})
|
|
29
|
+
with_optional_action_view_annotations do
|
|
30
|
+
html = render_to_string(template, locals: locals, **determine_layout(opts[:layout]))
|
|
31
|
+
if opts[:append_html].present?
|
|
32
|
+
html += opts[:append_html]
|
|
33
|
+
end
|
|
34
|
+
render html: html
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
protected
|
|
39
|
+
|
|
40
|
+
def with_optional_action_view_annotations(&block)
|
|
41
|
+
disable = Lookbook.config.preview_disable_action_view_annotations
|
|
42
|
+
ActionViewAnnotationsHandler.call(disable_annotations: disable, &block)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def permit_embeds
|
|
46
|
+
headers["X-Frame-Options"] = Lookbook.config.preview_embeds.policy
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -12,12 +12,14 @@ module Lookbook
|
|
|
12
12
|
YARD::Parser::SourceParser.after_parse_list { run_callbacks }
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def parse(&block)
|
|
15
|
+
def parse(files = nil, &block)
|
|
16
16
|
unless @parsing
|
|
17
17
|
@parsing = true
|
|
18
18
|
@after_parse_once_callbacks << block if block
|
|
19
|
+
files_list = files ? files.select { |file| file.to_s.end_with?(".rb") } : paths
|
|
20
|
+
|
|
19
21
|
YARD::Registry.clear
|
|
20
|
-
YARD.parse(
|
|
22
|
+
YARD.parse(files_list)
|
|
21
23
|
end
|
|
22
24
|
end
|
|
23
25
|
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
require "active_support"
|
|
2
|
+
|
|
3
|
+
module Lookbook
|
|
4
|
+
class Reloaders
|
|
5
|
+
attr_reader :reloaders
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
@reloaders = []
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def add(name, directories, extensions, &callback)
|
|
12
|
+
reloader = Reloader.new(name, directories, extensions, &callback)
|
|
13
|
+
reloaders.push(reloader)
|
|
14
|
+
|
|
15
|
+
if Engine.reloading?
|
|
16
|
+
Rails.application.reloaders << reloader
|
|
17
|
+
Rails.application.reloader.to_run { reloader.execute_if_updated }
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def execute
|
|
22
|
+
reloaders.each { |reloader| reloader.execute }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def register_changes(changes)
|
|
26
|
+
reloader = reloaders.find { |reloader| reloader.watching?(changes) }
|
|
27
|
+
reloader.last_changes = changes if reloader
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class Reloader
|
|
31
|
+
delegate :execute, :execute_if_updated, :updated?, to: :file_watcher
|
|
32
|
+
|
|
33
|
+
attr_reader :name, :directories, :extensions, :callback
|
|
34
|
+
attr_accessor :last_changes
|
|
35
|
+
|
|
36
|
+
def initialize(name, directories, extensions, &callback)
|
|
37
|
+
@name = name.to_sym
|
|
38
|
+
@directories = directories
|
|
39
|
+
@extensions = extensions
|
|
40
|
+
@callback = callback
|
|
41
|
+
@last_changes = nil
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def watching?(changes)
|
|
45
|
+
file_paths = changes.to_h.values.flatten
|
|
46
|
+
!!file_paths.find do |file_path|
|
|
47
|
+
file_path = Pathname(file_path).expand_path
|
|
48
|
+
directories.find do |dir_path|
|
|
49
|
+
matcher = File.expand_path(File.join(dir_path, "**"))
|
|
50
|
+
file_path.fnmatch?(matcher)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
protected
|
|
56
|
+
|
|
57
|
+
def file_watcher
|
|
58
|
+
return @_file_watcher if @_file_watcher
|
|
59
|
+
|
|
60
|
+
to_watch = directories.each_with_object({}) do |directory, result|
|
|
61
|
+
result[directory] = extensions
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
@_file_watcher ||= FileWatcher.new([], to_watch) do
|
|
65
|
+
callback.call(@last_changes)
|
|
66
|
+
@last_changes = nil
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|