lookbook 1.0.7 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/lookbook/css/lookbook.css +76 -2
  3. data/app/assets/lookbook/js/app.js +20 -2
  4. data/app/{components/lookbook/params_editor/field/component.js → assets/lookbook/js/components/params_input.js} +1 -14
  5. data/app/assets/lookbook/js/lookbook.js +2 -1
  6. data/app/components/lookbook/base_component.rb +2 -3
  7. data/app/components/lookbook/button/component.html.erb +2 -2
  8. data/app/components/lookbook/button/component.rb +6 -1
  9. data/app/components/lookbook/button_group/component.rb +3 -4
  10. data/app/components/lookbook/copy_button/component.html.erb +1 -1
  11. data/app/components/lookbook/debug_menu/component.html.erb +51 -0
  12. data/app/components/lookbook/debug_menu/component.rb +18 -0
  13. data/app/components/lookbook/embed/component.html.erb +3 -3
  14. data/app/components/lookbook/header/component.html.erb +19 -44
  15. data/app/components/lookbook/inspector_panel/component.html.erb +5 -3
  16. data/app/components/lookbook/inspector_panel/component.rb +6 -18
  17. data/app/components/lookbook/nav/component.js +4 -0
  18. data/app/components/lookbook/nav/component.rb +1 -1
  19. data/app/components/lookbook/nav/item/component.html.erb +4 -4
  20. data/app/components/lookbook/nav/item/component.rb +1 -1
  21. data/app/components/lookbook/page_tabs/component.html.erb +4 -4
  22. data/app/components/lookbook/page_tabs/component.rb +1 -1
  23. data/app/components/lookbook/params/editor/component.html.erb +21 -0
  24. data/app/components/lookbook/{params_editor → params/editor}/component.js +1 -1
  25. data/app/components/lookbook/params/editor/component.rb +40 -0
  26. data/app/components/lookbook/params/field/component.css +76 -0
  27. data/app/components/lookbook/params/field/component.html.erb +27 -0
  28. data/app/components/lookbook/params/field/component.js +7 -0
  29. data/app/components/lookbook/params/field/component.rb +101 -0
  30. data/app/components/lookbook/tabs/component.html.erb +2 -2
  31. data/app/components/lookbook/tag_component.rb +1 -0
  32. data/app/components/lookbook/viewport/component.css +1 -1
  33. data/app/components/lookbook/viewport/component.html.erb +11 -0
  34. data/app/controllers/lookbook/previews_controller.rb +1 -1
  35. data/app/helpers/lookbook/component_helper.rb +45 -26
  36. data/app/helpers/lookbook/page_helper.rb +1 -1
  37. data/app/views/layouts/lookbook/application.html.erb +18 -4
  38. data/app/views/layouts/lookbook/page.html.erb +4 -4
  39. data/app/views/layouts/lookbook/shell.html.erb +4 -4
  40. data/app/views/layouts/lookbook/skeleton.html.erb +0 -6
  41. data/app/views/lookbook/error.html.erb +1 -1
  42. data/app/views/lookbook/pages/show.html.erb +2 -2
  43. data/app/views/lookbook/previews/inputs/_color.html.erb +5 -0
  44. data/app/views/lookbook/previews/inputs/_range.html.erb +15 -0
  45. data/app/views/lookbook/previews/inputs/_select.html.erb +5 -0
  46. data/app/views/lookbook/previews/inputs/_text.html.erb +5 -0
  47. data/app/views/lookbook/previews/inputs/_textarea.html.erb +5 -0
  48. data/app/views/lookbook/previews/inputs/_toggle.html.erb +20 -0
  49. data/app/views/lookbook/previews/panels/_content.html.erb +2 -2
  50. data/app/views/lookbook/previews/panels/_notes.html.erb +2 -2
  51. data/app/views/lookbook/previews/panels/_output.html.erb +1 -1
  52. data/app/views/lookbook/previews/panels/_params.html.erb +3 -3
  53. data/app/views/lookbook/previews/panels/_preview.html.erb +1 -1
  54. data/app/views/lookbook/previews/panels/_source.html.erb +2 -2
  55. data/app/views/lookbook/previews/show.html.erb +13 -19
  56. data/lib/lookbook/config.rb +17 -1
  57. data/lib/lookbook/engine.rb +17 -7
  58. data/lib/lookbook/markdown.rb +1 -1
  59. data/lib/lookbook/panels.rb +14 -4
  60. data/lib/lookbook/params.rb +66 -35
  61. data/lib/lookbook/parser.rb +1 -0
  62. data/lib/lookbook/preview.rb +10 -4
  63. data/lib/lookbook/preview_controller.rb +11 -5
  64. data/lib/lookbook/preview_example.rb +2 -2
  65. data/lib/lookbook/source_inspector.rb +10 -4
  66. data/lib/lookbook/tag.rb +13 -3
  67. data/lib/lookbook/tag_options.rb +111 -0
  68. data/lib/lookbook/tags.rb +6 -2
  69. data/lib/lookbook/template_parser.rb +72 -0
  70. data/lib/lookbook/theme.rb +1 -1
  71. data/lib/lookbook/utils.rb +23 -0
  72. data/lib/lookbook/version.rb +1 -1
  73. data/lib/lookbook.rb +2 -0
  74. data/public/lookbook-assets/css/lookbook.css +369 -126
  75. data/public/lookbook-assets/css/lookbook.css.map +1 -1
  76. data/public/lookbook-assets/js/embed.js +13 -13
  77. data/public/lookbook-assets/js/embed.js.map +1 -1
  78. data/public/lookbook-assets/js/lookbook.js +772 -687
  79. data/public/lookbook-assets/js/lookbook.js.map +1 -1
  80. metadata +42 -10
  81. data/app/components/lookbook/params_editor/component.html.erb +0 -3
  82. data/app/components/lookbook/params_editor/component.rb +0 -11
  83. data/app/components/lookbook/params_editor/field/component.html.erb +0 -49
  84. data/app/components/lookbook/params_editor/field/component.rb +0 -44
@@ -6,13 +6,13 @@
6
6
  <h6 class="italic font-mono mb-4 opacity-40">
7
7
  # <%= item.label %>
8
8
  </h6>
9
- <%= render_component :prose, content: item.notes %>
9
+ <%= lookbook_render :prose, content: item.notes %>
10
10
  </div>
11
11
  <% end %>
12
12
  </div>
13
13
  <% else %>
14
14
  <div class="px-4 py-6 bg-lookbook-prose-bg w-full h-full">
15
- <%= render_component :prose do %>
15
+ <%= lookbook_render :prose do %>
16
16
  <%== items.any? ? items.first.notes : "<em class='opacity-50'>No notes provided.</em>" %>
17
17
  <% end %>
18
18
  </div>
@@ -1,4 +1,4 @@
1
- <%= render_component :code, line_numbers: true, full_height: true do -%>
1
+ <%= lookbook_render :code, line_numbers: true, full_height: true do -%>
2
2
  <% if examples.many? -%>
3
3
  <% examples.each do |example| -%><%== "<!-- #{example.label} -->\n#{beautify(example.output)}\n\n" -%><% end %>
4
4
  <%- else -%>
@@ -1,12 +1,12 @@
1
1
  <% if preview.params.none? %>
2
2
  <div class="p-4 w-full h-full bg-lookbook-prose-bg">
3
- <%= render_component :prose do %>
3
+ <%= lookbook_render :prose do %>
4
4
  <em class='opacity-50'>No params configured.</em>
5
5
  <% end %>
6
6
  </div>
7
7
  <% else %>
8
- <div class="py-3 h-full">
9
- <%= render_component :params_editor do |editor| %>
8
+ <div class="h-full overflow-x-hidden">
9
+ <%= lookbook_render "params/editor", inputs: Lookbook::Params.inputs do |editor| %>
10
10
  <% preview.params.each do |param| %>
11
11
  <% editor.field **param, value: params[param[:name]] %>
12
12
  <% end %>
@@ -1,4 +1,4 @@
1
- <%= render_component :viewport,
1
+ <%= lookbook_render :viewport,
2
2
  src: lookbook_preview_path(request.query_parameters.merge(lookbook_timestamp: Time.now)),
3
3
  alpine_data: "$store.inspector.main",
4
4
  class: "-inset-px relative",
@@ -1,11 +1,11 @@
1
1
  <div class="h-full">
2
2
  <% if examples.many? %>
3
- <%= render_component :code, language: examples.first.source_lang[:name], line_numbers: true, full_height: true do -%>
3
+ <%= lookbook_render :code, language: examples.first.source_lang[:name], line_numbers: true, full_height: true do -%>
4
4
  <%- examples.each.with_index(1) do |example, i| -%>
5
5
  <%== "#{sprintf example.source_lang[:comment], example.label}\n#{example.source}\n#{"\n" if i < examples.size}" %><% end %>
6
6
  <% end %>
7
7
  <% else %>
8
8
  <% example = examples.first %>
9
- <%= render_component :code, language: example.source_lang[:name], line_numbers: true, full_height: true do %><%== example.source %><% end %>
9
+ <%= lookbook_render :code, language: example.source_lang[:name], line_numbers: true, full_height: true do %><%== example.source %><% end %>
10
10
  <% end %>
11
11
  </div>
@@ -1,13 +1,13 @@
1
- <%= render_component :split_layout,
1
+ <%= lookbook_render :split_layout,
2
2
  alpine_data: "$store.layout.inspector",
3
3
  ":class": "($store.inspector.drawer.hidden || #{@drawer_panels.none?}) && '!grid-rows-[1fr] !grid-cols-[1fr]'" do |layout| %>
4
4
 
5
5
  <%= layout.pane class: "flex flex-col h-full overflow-hidden",
6
6
  "x-effect": "forceOrientation = (layoutWidth < $store.inspector.minVerticalSplitWidth) ? 'horizontal' : null" do %>
7
7
 
8
- <%= render_component :toolbar do |toolbar| %>
8
+ <%= lookbook_render :toolbar do |toolbar| %>
9
9
  <% toolbar.section ":class": "layoutResizing && 'overflow-hidden'" do %>
10
- <%= render_component :tabs, alpine_data: "$store.inspector.main" do |tabs| %>
10
+ <%= lookbook_render :tabs, alpine_data: "$store.inspector.main" do |tabs| %>
11
11
  <%= @main_panels.each do |panel| %>
12
12
  <% tabs.tab name: panel.name,
13
13
  label: panel.label,
@@ -17,19 +17,13 @@
17
17
  <% end %>
18
18
  <% end %>
19
19
 
20
- <% toolbar.section align: :right, padded: true, class: "flex-none min-w-[140px]", ":class": "{invisible: $store.inspector.main.activeTab !== 'preview'}" do %>
21
- <%= render_component :dimensions_display,
22
- target: "[data-component=viewport] iframe",
23
- class: "ml-auto opacity-30 hover:opacity-100" %>
24
- <% end %>
25
-
26
- <% toolbar.section divide: :left, class: "flex-none relative z-10" do %>
27
- <%= render_component :button_group do |group| %>
20
+ <% toolbar.section divide: :left, align: :right, class: "flex-none relative z-10" do %>
21
+ <%= lookbook_render :button_group do |group| %>
28
22
  <% if @pages.any? %>
29
23
  <% group.button icon: :code,
30
24
  tooltip: "Copy page embed code",
31
25
  copy: true do %>
32
- &lt;%= embed <%= @preview.preview_class %>, :<%= @target.name %>, params: <%= request.query_parameters.deep_symbolize_keys.to_s %> %&gt;
26
+ &lt;%= embed <%= @preview.preview_class_name %>, :<%= @target.name %>, params: <%= request.query_parameters.deep_symbolize_keys.to_s %> %&gt;
33
27
  <% end %>
34
28
  <% end %>
35
29
 
@@ -53,7 +47,7 @@
53
47
  <% end %>
54
48
 
55
49
  <div class="h-full relative overflow-auto">
56
- <%= render_component :tab_panels, alpine_data: "$store.inspector.main" do |tabs| %>
50
+ <%= lookbook_render :tab_panels, alpine_data: "$store.inspector.main" do |tabs| %>
57
51
  <% @main_panels.each do |panel| %>
58
52
  <% tabs.panel id: panel.id, name: panel.name, class: panel.panel_classes do %>
59
53
  <%= render panel.partial, **@inspector_data, panel: panel, **panel.locals %>
@@ -66,9 +60,9 @@
66
60
  <%= layout.pane class: "flex flex-col h-full overflow-hidden bg-lookbook-drawer-bg",
67
61
  "x-show": "!$store.inspector.drawer.hidden && #{@drawer_panels.any?}" do %>
68
62
 
69
- <%= render_component :toolbar do |toolbar| %>
63
+ <%= lookbook_render :toolbar do |toolbar| %>
70
64
  <% toolbar.section ":class": "layoutResizing && 'overflow-hidden'" do %>
71
- <%= render_component :tabs, alpine_data: "$store.inspector.drawer" do |tabs| %>
65
+ <%= lookbook_render :tabs, alpine_data: "$store.inspector.drawer" do |tabs| %>
72
66
  <%= @drawer_panels.each do |panel| %>
73
67
  <% tabs.tab name: panel.name,
74
68
  label: panel.label,
@@ -79,7 +73,7 @@
79
73
  <% end %>
80
74
 
81
75
  <% toolbar.section align: :right, class: "flex-none relative z-10" do %>
82
- <%= render_component :button_group do |group| %>
76
+ <%= lookbook_render :button_group do |group| %>
83
77
  <%= @drawer_panels.select { |p| !p.disabled && p.copy }.each do |panel| %>
84
78
  <% group.button icon: :copy,
85
79
  tooltip: "Copy panel contents",
@@ -93,7 +87,7 @@
93
87
  <% end %>
94
88
 
95
89
  <% toolbar.section divide: :left, class: "flex-none relative z-10" do %>
96
- <%= render_component :button_group do |group| %>
90
+ <%= lookbook_render :button_group do |group| %>
97
91
 
98
92
  <% group.button icon: :corner_up_right,
99
93
  tooltip: "Move drawer to right",
@@ -121,10 +115,10 @@
121
115
  <% end %>
122
116
 
123
117
  <div class="h-full overflow-auto">
124
- <%= render_component :tab_panels, alpine_data: "$store.inspector.drawer" do |tabs| %>
118
+ <%= lookbook_render :tab_panels, alpine_data: "$store.inspector.drawer" do |tabs| %>
125
119
  <% @drawer_panels.each do |panel| %>
126
120
  <% tabs.panel id: panel.id, name: panel.name, class: panel.panel_classes do %>
127
- <%= render_component :inspector_panel, **panel.slice(:id, :name, :system) do %>
121
+ <%= lookbook_render :inspector_panel, **panel.slice(:id, :name, :system) do %>
128
122
  <%= render panel.partial, **@inspector_data, panel: panel, **panel.locals %>
129
123
  <% end %>
130
124
  <% end %>
@@ -10,6 +10,7 @@ module Lookbook
10
10
  @options.set({
11
11
  project_name: "Lookbook",
12
12
  log_level: 2,
13
+ log_use_rails_logger: true,
13
14
  auto_refresh: true,
14
15
 
15
16
  components_path: "app/components",
@@ -24,6 +25,22 @@ module Lookbook
24
25
  preview_display_params: {},
25
26
  preview_srcdoc: nil,
26
27
  preview_tags: {},
28
+ preview_disable_action_view_annotations: true,
29
+ preview_param_inputs: {
30
+ select: "lookbook/previews/inputs/select",
31
+ textarea: "lookbook/previews/inputs/textarea",
32
+ toggle: "lookbook/previews/inputs/toggle",
33
+ color: "lookbook/previews/inputs/color",
34
+ range: "lookbook/previews/inputs/range",
35
+ text: "lookbook/previews/inputs/text",
36
+ email: "lookbook/previews/inputs/text",
37
+ number: "lookbook/previews/inputs/text",
38
+ tel: "lookbook/previews/inputs/text",
39
+ url: "lookbook/previews/inputs/text",
40
+ date: "lookbook/previews/inputs/text",
41
+ datetime_local: "lookbook/previews/inputs/text"
42
+ },
43
+ preview_params_options_eval: false,
27
44
  sort_examples: false,
28
45
 
29
46
  listen: Rails.env.development?,
@@ -32,7 +49,6 @@ module Lookbook
32
49
  listen_use_polling: false,
33
50
 
34
51
  cable_mount_path: "/cable",
35
- cable_logger: Lookbook.logger,
36
52
 
37
53
  parser_registry_path: "tmp/storage/.yardoc",
38
54
 
@@ -28,7 +28,13 @@ module Lookbook
28
28
  end
29
29
 
30
30
  def logger
31
- @logger ||= Rails.env.development? ? Logger.new($stdout) : Rails.logger
31
+ @logger ||= if Rails.logger.present? && config.log_use_rails_logger
32
+ Rails.logger
33
+ else
34
+ logger = Logger.new($stdout)
35
+ logger.level = config.log_level
36
+ logger
37
+ end
32
38
  end
33
39
 
34
40
  def debug_data
@@ -54,6 +60,13 @@ module Lookbook
54
60
  def theme
55
61
  @theme ||= Lookbook::Theme.new(config.ui_theme, config.ui_theme_overrides)
56
62
  end
63
+
64
+ def define_param_input(input, partial, input_options = nil)
65
+ config.preview_param_inputs[input.to_sym] = {
66
+ partial: partial,
67
+ input_options: input_options || {}
68
+ }
69
+ end
57
70
  end
58
71
 
59
72
  class Engine < Rails::Engine
@@ -72,10 +85,6 @@ module Lookbook
72
85
  config.lookbook.listen_paths << config.lookbook.components_path
73
86
  end
74
87
 
75
- initializer "lookbook.logging.development" do
76
- Lookbook.logger.level = Lookbook.config.log_level if Rails.env.development?
77
- end
78
-
79
88
  initializer "lookbook.parser.tags" do
80
89
  Lookbook::Parser.define_tags(Lookbook.config.preview_tags)
81
90
  end
@@ -131,6 +140,7 @@ module Lookbook
131
140
  if listen_paths.any?
132
141
  preview_listener = Listen.to(*listen_paths,
133
142
  only: /\.(#{config.listen_extensions.join("|")})$/,
143
+ wait_for_delay: 0.5,
134
144
  force_polling: config.listen_use_polling) do |modified, added, removed|
135
145
  parser.parse do
136
146
  run_hooks(:after_change, {modified: modified, added: added, removed: removed})
@@ -162,7 +172,7 @@ module Lookbook
162
172
  cable.cable = {adapter: "async"}.with_indifferent_access
163
173
  cable.mount_path = nil
164
174
  cable.connection_class = -> { Lookbook::Connection }
165
- cable.logger = config.cable_logger
175
+ cable.logger = Lookbook.logger
166
176
 
167
177
  @websocket ||= if Gem::Version.new(Rails.version) >= Gem::Version.new(6.0)
168
178
  ActionCable::Server::Base.new(config: cable)
@@ -174,7 +184,7 @@ module Lookbook
174
184
  end
175
185
 
176
186
  def websocket_mount_path
177
- "#{mounted_path}#{config.lookbook.cable_mount_path}" if websocket?
187
+ "#{mounted_path}#{config.lookbook.cable_mount_path}".gsub("//", "/") if websocket?
178
188
  end
179
189
 
180
190
  def websocket?
@@ -13,7 +13,7 @@ module Lookbook
13
13
  }
14
14
 
15
15
  def self.render(text)
16
- text&.gsub!(/<!-- (BEGIN|END) (.*) -->/, "")
16
+ Utils.strip_action_view_annotations!(text)
17
17
  markdown = Redcarpet::Markdown.new(Renderer, Lookbook.config.markdown_options)
18
18
  markdown.render(text).html_safe
19
19
  end
@@ -1,15 +1,25 @@
1
1
  module Lookbook
2
2
  module Panels
3
- def define_panel(name, opts = {})
4
- Lookbook.config.define_inspector_panel(name, opts)
3
+ def define_panel(name, *args)
4
+ Lookbook.config.define_inspector_panel(name, extract_opts(args))
5
5
  end
6
6
 
7
- def amend_panel(name, opts = {})
8
- Lookbook.amend_inspector_panel(name, opts)
7
+ def amend_panel(name, *args)
8
+ Lookbook.amend_inspector_panel(name, extract_opts(args))
9
9
  end
10
10
 
11
11
  def remove_panel(name)
12
12
  Lookbook.remove_inspector_panel(name)
13
13
  end
14
+
15
+ def extract_opts(args)
16
+ if args.many?
17
+ opts = args[1]
18
+ opts[:partial] = args[0]
19
+ opts
20
+ elsif args.any?
21
+ args[0].is_a?(String) ? {partial: args[0]} : args[0]
22
+ end
23
+ end
14
24
  end
15
25
  end
@@ -2,32 +2,68 @@ require "active_model"
2
2
 
3
3
  module Lookbook
4
4
  module Params
5
+ VALUE_TYPE_MATCH_REGEXP = /^(\[\s?([A-Z]{1}\w+)\s?\])/
6
+ DESCRIPTION_MATCH_REGEXP = /"(.*[^\\])"$/
7
+
8
+ PARAM_OPTION_KEYS = %i[name input label hint description value_type value_default].freeze
9
+
5
10
  class << self
6
- def build_param(param, default: nil, **opts)
7
- input, options_str = param.text.present? ? param.text.split(" ", 2) : [nil, ""]
8
- type = param.types&.first
9
- options = if options_str.present? && options_str.end_with?(".json")
10
- json_path = if options_str.start_with?(".")
11
- File.expand_path(options_str, File.dirname(param.object.files.first[0]))
12
- else
13
- Rails.root.join(options_str)
14
- end
15
- JSON.parse(File.read(json_path))
16
- else
17
- YAML.safe_load(options_str || "~")
11
+ def build_param(param, default: nil, eval_scope: nil)
12
+ input, value_type, options_str, description = parse_param_tag_text(param.text)
13
+
14
+ tag_options = Lookbook::TagOptions.new(options_str,
15
+ base_dir: (File.dirname(param.object.files.first[0]) if param.object.files.any?),
16
+ eval_scope: eval_scope).options
17
+
18
+ if tag_options.is_a? Array
19
+ # handle special case legacy situation for selects where
20
+ # options are an array of choices rather than a Hash
21
+ tag_options = {choices: tag_options}
18
22
  end
19
- input ||= guess_input(type, default)
20
- type ||= guess_type(input, default)
23
+
24
+ param_options = tag_options.select { |key| PARAM_OPTION_KEYS.include? key }
25
+ input_options = tag_options.except(*PARAM_OPTION_KEYS)
26
+
27
+ value_type ||= param_options[:value_type]
28
+ input ||= param_options[:input] || guess_input(value_type, default)
29
+ name = param.name.to_s
30
+
21
31
  {
22
- name: param.name,
23
- input: input_text?(input) ? "text" : input,
24
- input_type: (input if input_text?(input)),
25
- options: options,
26
- type: type,
27
- default: default
32
+ name: name,
33
+ label: param_options[:label] || name.titleize,
34
+ hint: param_options[:hint],
35
+ description: description || param_options[:description],
36
+ input: input.to_s.tr("_", "-"),
37
+ input_options: input_options,
38
+ value: nil,
39
+ value_type: value_type || guess_value_type(input, default),
40
+ value_default: default
28
41
  }
29
42
  end
30
43
 
44
+ # Parses param tag strings with the format: `[<value_type>] <input> <description?> <opts?>`
45
+ def parse_param_tag_text(text)
46
+ text = (text.presence || "").strip
47
+
48
+ value_type = nil
49
+ text.match(VALUE_TYPE_MATCH_REGEXP) do |m|
50
+ value_type = m[2]
51
+ text.gsub!(VALUE_TYPE_MATCH_REGEXP, "").strip!
52
+ end
53
+
54
+ text, options_str = Lookbook::TagOptions.extract_options(text)
55
+
56
+ description = nil
57
+ text.match(DESCRIPTION_MATCH_REGEXP) do |m|
58
+ description = m[1]
59
+ text.gsub!(DESCRIPTION_MATCH_REGEXP, "").strip!
60
+ end
61
+
62
+ input, rest = text.split(" ", 2)
63
+
64
+ [input, value_type, options_str, description, rest]
65
+ end
66
+
31
67
  def parse_method_param_str(param_str)
32
68
  return nil if param_str[0].nil? || param_str[1].nil?
33
69
  name = param_str[0].chomp(":")
@@ -81,17 +117,24 @@ module Lookbook
81
117
  end
82
118
  end
83
119
 
120
+ def inputs
121
+ @inputs ||= Lookbook.config.preview_param_inputs.map do |name, config|
122
+ config = {partial: config} if config.is_a?(String)
123
+ [name, {input_options: {}}.merge(config)]
124
+ end.to_h
125
+ end
126
+
84
127
  private
85
128
 
86
- def guess_input(type, default)
87
- if type&.downcase == "boolean" || (type.blank? && boolean?(default))
129
+ def guess_input(value_type, default)
130
+ if value_type&.downcase == "boolean" || (value_type.blank? && boolean?(default))
88
131
  "toggle"
89
132
  else
90
133
  "text"
91
134
  end
92
135
  end
93
136
 
94
- def guess_type(input, default)
137
+ def guess_value_type(input, default)
95
138
  if input&.downcase == "toggle"
96
139
  "Boolean"
97
140
  elsif input&.downcase == "number"
@@ -107,18 +150,6 @@ module Lookbook
107
150
  end
108
151
  end
109
152
 
110
- def input_text?(input)
111
- [
112
- "date",
113
- "datetime-local",
114
- "email",
115
- "number",
116
- "tel",
117
- "text",
118
- "url"
119
- ].include? input.to_s
120
- end
121
-
122
153
  def safe_parse_yaml(value, fallback)
123
154
  value.present? ? YAML.safe_load(value) : fallback
124
155
  rescue Psych::SyntaxError
@@ -39,6 +39,7 @@ module Lookbook
39
39
  YARD::Tags::Library.define_tag("Position", :position)
40
40
  YARD::Tags::Library.define_tag("ID", :id)
41
41
  YARD::Tags::Library.define_tag("Component", :component)
42
+ YARD::Tags::Library.define_tag("Param", :param, :with_name)
42
43
  custom.each do |name, opts|
43
44
  YARD::Tags::Library.define_tag(name.to_s.titleize, name)
44
45
  end
@@ -7,7 +7,7 @@ module Lookbook
7
7
 
8
8
  def initialize(preview, code_object)
9
9
  @preview = preview
10
- @preview_inspector = SourceInspector.new(code_object)
10
+ @preview_inspector = SourceInspector.new(code_object, eval_scope: preview_class.new)
11
11
  super(preview_class_path(@preview.name))
12
12
  end
13
13
 
@@ -15,10 +15,14 @@ module Lookbook
15
15
  @preview_inspector&.id || generate_id(lookup_path)
16
16
  end
17
17
 
18
- def preview_class
18
+ def preview_class_name
19
19
  @preview.name
20
20
  end
21
21
 
22
+ def preview_class
23
+ @preview
24
+ end
25
+
22
26
  def label
23
27
  @preview_inspector&.label&.presence || lookup_path.split("/").last.titleize
24
28
  end
@@ -143,10 +147,12 @@ module Lookbook
143
147
 
144
148
  sorted_previews = previews.compact.sort_by { |preview| [preview.position, preview.label] }
145
149
  @previews = PreviewCollection.new(sorted_previews)
146
- else
150
+ @previews
151
+ elsif !@preview_objects.present?
147
152
  PreviewCollection.new([])
153
+ else
154
+ @previews
148
155
  end
149
- @previews
150
156
  end
151
157
 
152
158
  def errors
@@ -11,16 +11,22 @@ module Lookbook
11
11
  opts = {}
12
12
  opts[:layout] = nil
13
13
  opts[:locals] = locals if locals.present?
14
- render html: render_to_string(template, **opts)
14
+
15
+ Utils.with_optional_action_view_annotations do
16
+ render html: render_to_string(template, **opts)
17
+ end
15
18
  end
16
19
 
17
20
  def render_in_layout_to_string(template, locals, opts = {})
18
21
  append_view_path Lookbook::Engine.root.join("app/views")
19
- html = render_to_string(template, locals: locals, **determine_layout(opts[:layout]))
20
- if opts[:append_html].present?
21
- html += opts[:append_html]
22
+
23
+ Utils.with_optional_action_view_annotations do
24
+ html = render_to_string(template, locals: locals, **determine_layout(opts[:layout]))
25
+ if opts[:append_html].present?
26
+ html += opts[:append_html]
27
+ end
28
+ render html: html
22
29
  end
23
- render html: html
24
30
  end
25
31
  end
26
32
  end
@@ -6,7 +6,7 @@ module Lookbook
6
6
  def initialize(name, preview, code_object)
7
7
  @name = name
8
8
  @preview = preview
9
- @example_inspector = SourceInspector.new(code_object)
9
+ @example_inspector = SourceInspector.new(code_object, eval_scope: @preview.preview_class.new)
10
10
  super("#{@preview.path}/#{name}")
11
11
  end
12
12
 
@@ -27,7 +27,7 @@ module Lookbook
27
27
  end
28
28
 
29
29
  def method_source
30
- @example_inspector.source.split("\n")[1..-2].join("\n").strip_heredoc
30
+ @example_inspector.source.sub(/^def \w+\s?(\([^)]+\))?/m, "").split("\n")[0..-2].join("\n").strip_heredoc.strip
31
31
  end
32
32
 
33
33
  def lang
@@ -5,8 +5,9 @@ module Lookbook
5
5
  attr_reader :code_object
6
6
  delegate :groups, :source, to: :@code_object, allow_nil: true
7
7
 
8
- def initialize(code_object)
8
+ def initialize(code_object, eval_scope: nil)
9
9
  @code_object = code_object
10
+ @eval_scope = eval_scope
10
11
  end
11
12
 
12
13
  def hidden?
@@ -74,8 +75,11 @@ module Lookbook
74
75
  end
75
76
 
76
77
  def params
77
- code_object&.tags("param")&.map do |param|
78
- Lookbook::Params.build_param(param, default: parameter_defaults[param.name])
78
+ @params ||= {}
79
+ @params[:param] ||= code_object&.tags("param")&.map do |param|
80
+ Lookbook::Params.build_param(param,
81
+ default: parameter_defaults[param.name],
82
+ eval_scope: @eval_scope)
79
83
  end
80
84
  end
81
85
 
@@ -85,7 +89,9 @@ module Lookbook
85
89
 
86
90
  def tags(name = nil)
87
91
  tag_objects = code_object&.tags(name).presence || []
88
- Lookbook::Tags.process_tags(tag_objects)
92
+ Lookbook::Tags.process_tags(tag_objects,
93
+ eval_scope: @eval_scope,
94
+ file: (code_object.files.first[0] if code_object.files.any?))
89
95
  end
90
96
 
91
97
  def tag(name = nil)
data/lib/lookbook/tag.rb CHANGED
@@ -5,13 +5,15 @@ module Lookbook
5
5
  attr_reader :data, :arg_names
6
6
  attr_accessor :args, :opts
7
7
 
8
- def initialize(tag_object, arg_names = nil, parser: nil, **options)
8
+ def initialize(tag_object, arg_names = nil, parser: nil, eval_scope: nil, file: nil, **options)
9
9
  @tag_object = tag_object
10
10
  @arg_names = arg_names
11
11
  @args = {}
12
12
  @opts = {}
13
13
  @options = options
14
14
  @parser = parser
15
+ @eval_scope = eval_scope
16
+ @file = file
15
17
  @data = Store.new
16
18
  run_parser
17
19
  end
@@ -43,8 +45,16 @@ module Lookbook
43
45
 
44
46
  def parse_opts
45
47
  return @opts if @options[:parse_options] == false
46
- parsed_opts = parse_yaml(opts_str)
47
- @opts = parsed_opts.is_a?(Hash) ? parsed_opts.with_indifferent_access : {}
48
+ tag_opts = Lookbook::TagOptions.new(opts_str,
49
+ eval_scope: @eval_scope,
50
+ base_dir: File.dirname(@file))
51
+ options = tag_opts.resolve || {}
52
+ @opts = if options.is_a?(Hash)
53
+ options.with_indifferent_access
54
+ else
55
+ Lookbook.logger.warn "'@#{tag_name}' tag options should resolve to a Hash"
56
+ options
57
+ end
48
58
  end
49
59
 
50
60
  def run_parser