lookbook 1.0.8 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) 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/helpers/lookbook/preview_helper.rb +1 -1
  38. data/app/views/layouts/lookbook/application.html.erb +18 -4
  39. data/app/views/layouts/lookbook/page.html.erb +4 -4
  40. data/app/views/layouts/lookbook/shell.html.erb +4 -4
  41. data/app/views/layouts/lookbook/skeleton.html.erb +0 -6
  42. data/app/views/lookbook/error.html.erb +1 -1
  43. data/app/views/lookbook/pages/show.html.erb +2 -2
  44. data/app/views/lookbook/preview.html.erb +1 -1
  45. data/app/views/lookbook/previews/inputs/_color.html.erb +5 -0
  46. data/app/views/lookbook/previews/inputs/_range.html.erb +15 -0
  47. data/app/views/lookbook/previews/inputs/_select.html.erb +5 -0
  48. data/app/views/lookbook/previews/inputs/_text.html.erb +5 -0
  49. data/app/views/lookbook/previews/inputs/_textarea.html.erb +5 -0
  50. data/app/views/lookbook/previews/inputs/_toggle.html.erb +20 -0
  51. data/app/views/lookbook/previews/panels/_content.html.erb +2 -2
  52. data/app/views/lookbook/previews/panels/_notes.html.erb +2 -2
  53. data/app/views/lookbook/previews/panels/_output.html.erb +1 -1
  54. data/app/views/lookbook/previews/panels/_params.html.erb +3 -3
  55. data/app/views/lookbook/previews/panels/_preview.html.erb +1 -1
  56. data/app/views/lookbook/previews/panels/_source.html.erb +2 -2
  57. data/app/views/lookbook/previews/show.html.erb +13 -19
  58. data/lib/lookbook/config.rb +111 -100
  59. data/lib/lookbook/engine.rb +3 -60
  60. data/lib/lookbook/markdown.rb +1 -1
  61. data/lib/lookbook/panels.rb +14 -4
  62. data/lib/lookbook/params.rb +66 -35
  63. data/lib/lookbook/parser.rb +1 -0
  64. data/lib/lookbook/preview.rb +10 -4
  65. data/lib/lookbook/preview_controller.rb +7 -19
  66. data/lib/lookbook/preview_example.rb +1 -1
  67. data/lib/lookbook/source_inspector.rb +10 -4
  68. data/lib/lookbook/store.rb +14 -28
  69. data/lib/lookbook/tag.rb +13 -3
  70. data/lib/lookbook/tag_options.rb +111 -0
  71. data/lib/lookbook/tags.rb +6 -2
  72. data/lib/lookbook/template_parser.rb +72 -0
  73. data/lib/lookbook/theme.rb +1 -1
  74. data/lib/lookbook/utils.rb +23 -0
  75. data/lib/lookbook/version.rb +1 -1
  76. data/lib/lookbook.rb +75 -28
  77. data/public/lookbook-assets/css/lookbook.css +369 -126
  78. data/public/lookbook-assets/css/lookbook.css.map +1 -1
  79. data/public/lookbook-assets/js/embed.js +13 -13
  80. data/public/lookbook-assets/js/embed.js.map +1 -1
  81. data/public/lookbook-assets/js/lookbook.js +701 -612
  82. data/public/lookbook-assets/js/lookbook.js.map +1 -1
  83. metadata +56 -11
  84. data/app/components/lookbook/params_editor/component.html.erb +0 -3
  85. data/app/components/lookbook/params_editor/component.rb +0 -11
  86. data/app/components/lookbook/params_editor/field/component.html.erb +0 -49
  87. data/app/components/lookbook/params_editor/field/component.rb +0 -44
  88. data/lib/lookbook/data.rb +0 -11
@@ -1,11 +1,11 @@
1
1
  <div class="p-4 bg-lookbook-prose-bg h-full">
2
2
  <% if panel.content.present? %>
3
- <%= render_component :prose, markdown: true do %>
3
+ <%= lookbook_render :prose, markdown: true do %>
4
4
  <%== panel.content %>
5
5
  <% end %>
6
6
  <% else %>
7
7
  <% if Rails.env.development? %>
8
- <%= render_component :prose do %>
8
+ <%= lookbook_render :prose do %>
9
9
  <em class='opacity-50'>No content has been defined for this panel.</em>
10
10
  <% end %>
11
11
  <% end %>
@@ -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 %>
@@ -1,107 +1,118 @@
1
- require "lookbook/markdown"
2
- require "lookbook/theme"
3
- require "lookbook/store"
4
-
5
1
  module Lookbook
6
2
  class Config
7
- def initialize
8
- @options = Store.new({}, true)
9
-
10
- @options.set({
11
- project_name: "Lookbook",
12
- log_level: 2,
13
- auto_refresh: true,
14
-
15
- components_path: "app/components",
16
-
17
- page_controller: "Lookbook::PageController",
18
- page_route: "pages",
19
- page_paths: ["test/components/docs"],
20
- page_options: {},
21
- markdown_options: Markdown::DEFAULT_OPTIONS,
22
-
23
- preview_paths: [],
24
- preview_display_params: {},
25
- preview_srcdoc: nil,
26
- preview_tags: {},
27
- preview_disable_action_view_annotations: true,
28
- sort_examples: false,
29
-
30
- listen: Rails.env.development?,
31
- listen_paths: [],
32
- listen_extensions: ["rb", "html.*"],
33
- listen_use_polling: false,
34
-
35
- cable_mount_path: "/cable",
36
- cable_logger: Lookbook.logger,
37
-
38
- parser_registry_path: "tmp/storage/.yardoc",
39
-
40
- ui_theme: "indigo",
41
- ui_theme_overrides: {},
42
- ui_favicon: true,
43
-
44
- hooks: {
45
- after_initialize: [],
46
- before_exit: [],
47
- after_change: []
3
+ DEFAULTS = {
4
+ project_name: "Lookbook",
5
+ log_level: 2,
6
+ log_use_rails_logger: true,
7
+ auto_refresh: true,
8
+
9
+ components_path: "app/components",
10
+
11
+ page_controller: "Lookbook::PageController",
12
+ page_route: "pages",
13
+ page_paths: ["test/components/docs"],
14
+ page_options: {},
15
+ markdown_options: Markdown::DEFAULT_OPTIONS,
16
+
17
+ preview_paths: [],
18
+ preview_display_params: {},
19
+ preview_srcdoc: nil,
20
+ preview_tags: {},
21
+ preview_disable_action_view_annotations: true,
22
+ preview_param_inputs: {
23
+ select: "lookbook/previews/inputs/select",
24
+ textarea: "lookbook/previews/inputs/textarea",
25
+ toggle: "lookbook/previews/inputs/toggle",
26
+ color: "lookbook/previews/inputs/color",
27
+ range: "lookbook/previews/inputs/range",
28
+ text: "lookbook/previews/inputs/text",
29
+ email: "lookbook/previews/inputs/text",
30
+ number: "lookbook/previews/inputs/text",
31
+ tel: "lookbook/previews/inputs/text",
32
+ url: "lookbook/previews/inputs/text",
33
+ date: "lookbook/previews/inputs/text",
34
+ datetime_local: "lookbook/previews/inputs/text"
35
+ },
36
+ preview_params_options_eval: false,
37
+ sort_examples: false,
38
+
39
+ listen: Rails.env.development?,
40
+ listen_paths: [],
41
+ listen_extensions: ["rb", "html.*"],
42
+ listen_use_polling: false,
43
+
44
+ cable_mount_path: "/cable",
45
+
46
+ parser_registry_path: "tmp/storage/.yardoc",
47
+
48
+ ui_theme: "indigo",
49
+ ui_theme_overrides: {},
50
+ ui_favicon: true,
51
+
52
+ hooks: {
53
+ after_initialize: [],
54
+ before_exit: [],
55
+ after_change: []
56
+ },
57
+
58
+ debug_menu: Rails.env.development?,
59
+
60
+ experimental_features: false,
61
+
62
+ inspector_panels: {
63
+ preview: {
64
+ pane: :main,
65
+ position: 1,
66
+ partial: "lookbook/previews/panels/preview",
67
+ hotkey: "v",
68
+ panel_classes: "overflow-hidden",
69
+ padded: false,
70
+ system: true
48
71
  },
49
-
50
- debug_menu: Rails.env.development?,
51
-
52
- experimental_features: false,
53
-
54
- inspector_panels: {
55
- preview: {
56
- pane: :main,
57
- position: 1,
58
- partial: "lookbook/previews/panels/preview",
59
- hotkey: "v",
60
- panel_classes: "overflow-hidden",
61
- padded: false,
62
- system: true
63
- },
64
- output: {
65
- pane: :main,
66
- position: 2,
67
- partial: "lookbook/previews/panels/output",
68
- label: "HTML",
69
- hotkey: "h",
70
- padded: false,
71
- system: true
72
- },
73
- source: {
74
- pane: :drawer,
75
- position: 1,
76
- partial: "lookbook/previews/panels/source",
77
- label: "Source",
78
- hotkey: "s",
79
- copy: ->(data) { data.examples.map { |e| e.source }.join("\n") },
80
- padded: false,
81
- system: true
82
- },
83
- notes: {
84
- pane: :drawer,
85
- position: 2,
86
- partial: "lookbook/previews/panels/notes",
87
- label: "Notes",
88
- hotkey: "n",
89
- disabled: ->(data) { data.examples.select { |e| e.notes.present? }.none? },
90
- padded: false,
91
- system: true
92
- },
93
- params: {
94
- pane: :drawer,
95
- position: 3,
96
- partial: "lookbook/previews/panels/params",
97
- label: "Params",
98
- hotkey: "p",
99
- disabled: ->(data) { data.preview.params.none? },
100
- padded: false,
101
- system: true
102
- }
72
+ output: {
73
+ pane: :main,
74
+ position: 2,
75
+ partial: "lookbook/previews/panels/output",
76
+ label: "HTML",
77
+ hotkey: "h",
78
+ padded: false,
79
+ system: true
80
+ },
81
+ source: {
82
+ pane: :drawer,
83
+ position: 1,
84
+ partial: "lookbook/previews/panels/source",
85
+ label: "Source",
86
+ hotkey: "s",
87
+ copy: ->(data) { data.examples.map { |e| e.source }.join("\n") },
88
+ padded: false,
89
+ system: true
90
+ },
91
+ notes: {
92
+ pane: :drawer,
93
+ position: 2,
94
+ partial: "lookbook/previews/panels/notes",
95
+ label: "Notes",
96
+ hotkey: "n",
97
+ disabled: ->(data) { data.examples.select { |e| e.notes.present? }.none? },
98
+ padded: false,
99
+ system: true
100
+ },
101
+ params: {
102
+ pane: :drawer,
103
+ position: 3,
104
+ partial: "lookbook/previews/panels/params",
105
+ label: "Params",
106
+ hotkey: "p",
107
+ disabled: ->(data) { data.preview.params.none? },
108
+ padded: false,
109
+ system: true
103
110
  }
104
- })
111
+ }
112
+ }
113
+
114
+ def initialize
115
+ @options = Store.new(Config::DEFAULTS, recursive: true)
105
116
  end
106
117
 
107
118
  def runtime_parsing=(value)
@@ -3,64 +3,11 @@ require "action_cable/engine"
3
3
  require "listen"
4
4
 
5
5
  module Lookbook
6
- autoload :Config, "lookbook/config"
7
- autoload :Data, "lookbook/data"
8
- autoload :Hooks, "lookbook/hooks"
9
- autoload :Panels, "lookbook/panels"
10
- autoload :Tags, "lookbook/tags"
11
-
12
- class << self
13
- include Lookbook::Data
14
- include Lookbook::Hooks
15
- include Lookbook::Panels
16
- include Lookbook::Tags
17
-
18
- def version
19
- Lookbook::VERSION
20
- end
21
-
22
- def config
23
- @config ||= Config.new
24
- end
25
-
26
- def configure
27
- yield(config)
28
- end
29
-
30
- def logger
31
- @logger ||= Rails.env.development? ? Logger.new($stdout) : Rails.logger
32
- end
33
-
34
- def debug_data
35
- {
36
- version: version,
37
- env: Rails.env.to_s,
38
- config: config.to_h
39
- }
40
- end
41
-
42
- def previews
43
- Preview.all
44
- end
45
-
46
- def pages
47
- Page.all
48
- end
49
-
50
- def broadcast(event_name, data = {})
51
- Engine.websocket&.broadcast(event_name.to_s, data)
52
- end
53
-
54
- def theme
55
- @theme ||= Lookbook::Theme.new(config.ui_theme, config.ui_theme_overrides)
56
- end
57
- end
58
-
59
6
  class Engine < Rails::Engine
60
7
  isolate_namespace Lookbook
61
8
 
62
- config.lookbook = Lookbook.config
63
9
  config.autoload_paths << File.expand_path(Lookbook::Engine.root.join("app/components"))
10
+ config.lookbook = Lookbook.config
64
11
 
65
12
  initializer "lookbook.viewcomponent.config" do
66
13
  config.lookbook.preview_paths += config.view_component.preview_paths
@@ -72,10 +19,6 @@ module Lookbook
72
19
  config.lookbook.listen_paths << config.lookbook.components_path
73
20
  end
74
21
 
75
- initializer "lookbook.logging.development" do
76
- Lookbook.logger.level = Lookbook.config.log_level if Rails.env.development?
77
- end
78
-
79
22
  initializer "lookbook.parser.tags" do
80
23
  Lookbook::Parser.define_tags(Lookbook.config.preview_tags)
81
24
  end
@@ -125,12 +68,12 @@ module Lookbook
125
68
  def init_listeners
126
69
  config = Lookbook.config
127
70
  return unless config.listen == true
128
- Listen.logger = Lookbook.logger
129
71
 
130
72
  listen_paths = config.listen_paths.uniq
131
73
  if listen_paths.any?
132
74
  preview_listener = Listen.to(*listen_paths,
133
75
  only: /\.(#{config.listen_extensions.join("|")})$/,
76
+ wait_for_delay: 0.5,
134
77
  force_polling: config.listen_use_polling) do |modified, added, removed|
135
78
  parser.parse do
136
79
  run_hooks(:after_change, {modified: modified, added: added, removed: removed})
@@ -162,7 +105,7 @@ module Lookbook
162
105
  cable.cable = {adapter: "async"}.with_indifferent_access
163
106
  cable.mount_path = nil
164
107
  cable.connection_class = -> { Lookbook::Connection }
165
- cable.logger = config.cable_logger
108
+ cable.logger = Lookbook.logger
166
109
 
167
110
  @websocket ||= if Gem::Version.new(Rails.version) >= Gem::Version.new(6.0)
168
111
  ActionCable::Server::Base.new(config: cable)
@@ -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