lookbook 1.0.1 → 1.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ff67ef3eb53b5a6605d46fdf186f859709112f09debfc72bab1a3f766475ea7b
4
- data.tar.gz: c592dfa672ad57776c5c9ffb38dafc82998c51ca68c02fcfe7b7bc980e519ccd
3
+ metadata.gz: fd24f301fb1e05131ba58a2d236b15155f38b372c52ada4823ea6f76111dc0b1
4
+ data.tar.gz: 8675198f147aa93461a89964ad2b28461facdd672088b3edfe0880ea1b293545
5
5
  SHA512:
6
- metadata.gz: 7b0fc0d0a54945f24a543d18b44e1734453e166286823e85f17ed9f5d51235e3e4cd9733287089dc76c58617047fd4835a1051c5dbe8836c05fc8b1d7c36ec3f
7
- data.tar.gz: 551d4744fb346cb835c53e26167f4a6e2fa71b612d2b212a7968b802775ac91655e15ac4f1ae4faf3d2fada0a95d7f7e1b7ecd581adb33b0ac49941cf508ccc1
6
+ metadata.gz: 5a9e80161cf8880083c2138144304dfc5427478c8114073f9409e3fb883eddf9abe7e055aea33b16625316c15be15fd139b8ab3607d808ff90419b5ad95b4eab
7
+ data.tar.gz: 1e1836fdad458167f63e3736d3d99107b1a0346da530fe57f9be03eb188c029d5891c8534999475673aa78fd02c645c37edb181b5960165316172bcf5cded59b
@@ -31,11 +31,19 @@ module Lookbook
31
31
  nil
32
32
  end
33
33
 
34
+ def alpine_encode(data)
35
+ if data.is_a? String
36
+ "\'#{json_escape data}\'"
37
+ else
38
+ json_escape data.to_json.tr("\"", "\'")
39
+ end
40
+ end
41
+
34
42
  def prepare_alpine_data(x_data = nil)
35
43
  alpine_component_name = x_data || @html_attrs&.dig(:"x-data") || alpine_component
36
44
  if alpine_component_name.present?
37
- args = Array.wrap(alpine_data)
38
- args.any? ? "#{alpine_component_name}(#{safe_join(args)})" : alpine_component_name
45
+ args = Array.wrap(alpine_data).compact
46
+ args.any? ? "#{alpine_component_name}(#{args.join(",")})" : alpine_component_name
39
47
  end
40
48
  end
41
49
  end
@@ -13,7 +13,7 @@ module Lookbook
13
13
  protected
14
14
 
15
15
  def alpine_data
16
- content ? nil : @target.to_json
16
+ content ? nil : alpine_encode(@target)
17
17
  end
18
18
 
19
19
  def alpine_component
@@ -2,15 +2,12 @@ module Lookbook
2
2
  class DimensionsDisplay::Component < Lookbook::BaseComponent
3
3
  def initialize(target:, **html_attrs)
4
4
  @target = target
5
+ @alpine_data = alpine_encode(@target)
5
6
  super(**html_attrs)
6
7
  end
7
8
 
8
9
  protected
9
10
 
10
- def alpine_data
11
- @target.to_json
12
- end
13
-
14
11
  def alpine_component
15
12
  "dimensionsDisplayComponent"
16
13
  end
@@ -1,19 +1,19 @@
1
- <% if @example.present? %>
1
+ <% if @target.present? %>
2
2
  <%= render_component_tag class: "not-prose border-b border-lookbook-divider rounded-sm overflow-hidden", "@navigation:start.window": "cleanup" do %>
3
3
 
4
4
  <%= render_component :toolbar, class: "border border-b-0 border-lookbook-divider" do |toolbar| %>
5
5
  <% toolbar.section padded: true do %>
6
6
  <h3>
7
- <%= @example.preview.label %> (<%= @example.label %>)
7
+ <%= @target.preview.label %> (<%= @target.label %>)
8
8
  </h3>
9
9
  <% end %>
10
10
  <% toolbar.section align: :right, divide: :left do %>
11
11
  <%= render_component :button_group do |group| %>
12
12
  <% group.button icon: :eye,
13
- href: lookbook_inspect_path(@example.path, @params),
13
+ href: lookbook_inspect_path(@target.path, @params),
14
14
  tooltip: "View in Inspector" %>
15
15
  <% group.button icon: :external_link,
16
- href: lookbook_preview_path(@example.path, @params),
16
+ href: lookbook_preview_path(@target.path, @params),
17
17
  tooltip: "Open in new window",
18
18
  target: "_blank" %>
19
19
  <% end %>
@@ -28,7 +28,7 @@
28
28
  @viewport:resize-complete="resizeIframe"
29
29
  @tabs:change.window="resizeIframe">
30
30
  <%= render_component :viewport,
31
- src: lookbook_preview_path(@example.path, @params.merge(lookbook_embed: true)),
31
+ src: lookbook_preview_path(@target.path, @params.merge(lookbook_embed: true)),
32
32
  alpine_data: "store",
33
33
  resize_height: false,
34
34
  max_height: @max_height,
@@ -2,7 +2,7 @@ module Lookbook
2
2
  class Embed::Component < Lookbook::BaseComponent
3
3
  def initialize(id:, example:, params: {}, opts: {}, max_height: nil, **html_attrs)
4
4
  @id = id
5
- @example = example
5
+ @target = example
6
6
  @params = params
7
7
  @opts = opts
8
8
  @max_height = max_height
@@ -20,7 +20,7 @@ module Lookbook
20
20
  end
21
21
 
22
22
  def alpine_data
23
- [@id.to_json, "$store.pages.embeds"].join(",")
23
+ [alpine_encode(@id), "$store.pages.embeds"].join(",")
24
24
  end
25
25
 
26
26
  def alpine_component
@@ -1,4 +1,4 @@
1
- <%= render_component_tag :i, style: "height: #{size_rems}; width: #{size_rems}" do %>
1
+ <%= render_component_tag :i, style: "height: #{size_rems}; width: #{size_rems}; #{@html_attrs[:style]}" do %>
2
2
  <svg>
3
3
  <use :href="`/lookbook-assets/feather-sprite.svg#${iconName}`" x-cloak />
4
4
  </svg>
@@ -1,7 +1,7 @@
1
1
  module Lookbook
2
2
  class Icon::Component < Lookbook::BaseComponent
3
3
  def initialize(name:, size: 4, **html_attrs)
4
- @icon_name = name.is_a?(Symbol) ? name.to_s.tr("_", "-").to_json : name
4
+ @alpine_data = name.is_a?(Symbol) ? alpine_encode(name.to_s.tr("_", "-")) : name
5
5
  @size = size || 4
6
6
  super(**html_attrs)
7
7
  end
@@ -12,10 +12,6 @@ module Lookbook
12
12
 
13
13
  protected
14
14
 
15
- def alpine_data
16
- @icon_name
17
- end
18
-
19
15
  def alpine_component
20
16
  "iconComponent"
21
17
  end
@@ -78,10 +78,10 @@ module Lookbook
78
78
  protected
79
79
 
80
80
  def alpine_data
81
- {
81
+ alpine_encode({
82
82
  id: @item.id,
83
83
  matchers: item.is_a?(Lookbook::Collection) ? nil : item.matchers
84
- }.to_json
84
+ })
85
85
  end
86
86
 
87
87
  def alpine_component
@@ -33,7 +33,7 @@ module Lookbook
33
33
  protected
34
34
 
35
35
  def alpine_data
36
- escaped_value = helpers.raw json_escape(value.to_json)
36
+ escaped_value = json_escape(value.to_json)
37
37
  "{name: '#{name}', value: #{escaped_value}}"
38
38
  end
39
39
 
@@ -13,7 +13,7 @@ module Lookbook
13
13
  before_action :set_params
14
14
 
15
15
  def preview
16
- if @example
16
+ if @target
17
17
  begin
18
18
  opts = {layout: @preview.layout}
19
19
  if params[:lookbook_embed] == "true"
@@ -32,7 +32,7 @@ module Lookbook
32
32
  end
33
33
 
34
34
  def show
35
- if @example
35
+ if @target
36
36
  begin
37
37
  @main_panels = main_panels
38
38
  @drawer_panels = drawer_panels
@@ -52,9 +52,9 @@ module Lookbook
52
52
  private
53
53
 
54
54
  def lookup_entities
55
- @example = Lookbook.previews.find_example(params[:path])
56
- if @example.present?
57
- @preview = @example.preview
55
+ @target = Lookbook.previews.find_example(params[:path])
56
+ if @target.present?
57
+ @preview = @target.preview
58
58
  if params[:path] == @preview&.lookup_path
59
59
  redirect_to lookbook_inspect_path "#{params[:path]}/#{@preview.default_example.name}"
60
60
  end
@@ -85,17 +85,17 @@ module Lookbook
85
85
  end
86
86
 
87
87
  def target_examples
88
- @example.type == :group ? @example.examples : [@example]
88
+ @target.type == :group ? @target.examples : [@target]
89
89
  end
90
90
 
91
91
  def set_title
92
- @title = @example.present? ? [@example&.label, @preview&.label].compact.join(" :: ") : "Not found"
92
+ @title = @target.present? ? [@target&.label, @preview&.label].compact.join(" :: ") : "Not found"
93
93
  end
94
94
 
95
95
  def set_params
96
- if @example
96
+ if @target
97
97
  # cast known params to type
98
- @example.params.each do |param|
98
+ @target.params.each do |param|
99
99
  if preview_controller.params.key?(param[:name])
100
100
  preview_controller.params[param[:name]] = Lookbook::Params.cast(preview_controller.params[param[:name]], param[:type])
101
101
  end
@@ -103,7 +103,7 @@ module Lookbook
103
103
  # set display and data params
104
104
  preview_controller.params.merge!({
105
105
  lookbook: {
106
- display: @example.display_params,
106
+ display: @target.display_params,
107
107
  data: Lookbook.data
108
108
  }
109
109
  })
@@ -113,7 +113,7 @@ module Lookbook
113
113
  def preview_params
114
114
  preview_controller.params.permit!
115
115
  preview_controller.params.to_h.select do |key, value|
116
- !!@example.params.find { |param| param[:name] == key }
116
+ !!@target.params.find { |param| param[:name] == key }
117
117
  end
118
118
  end
119
119
 
@@ -125,12 +125,7 @@ module Lookbook
125
125
  path: params[:path]
126
126
  }
127
127
 
128
- example = @example
129
128
  preview = @preview
130
- preview.define_singleton_method(:params, proc {
131
- example.params
132
- })
133
-
134
129
  examples = target_examples.map do |example|
135
130
  render_args = @preview.render_args(example.name, params: preview_controller.params)
136
131
  has_template = render_args[:template] != "view_components/preview"
@@ -144,11 +139,18 @@ module Lookbook
144
139
  example
145
140
  end
146
141
 
142
+ target = @target.type == :group ? @target : examples.find { |e| e.lookup_path == @target.lookup_path }
143
+
144
+ preview.define_singleton_method(:params, proc {
145
+ target.params
146
+ })
147
+
147
148
  @inspector_data ||= Lookbook::Store.new({
148
149
  context: context_data,
149
150
  preview: preview,
150
151
  examples: examples,
151
- example: example,
152
+ example: examples.first,
153
+ target: target,
152
154
  data: Lookbook.data,
153
155
  app: Lookbook
154
156
  })
@@ -198,7 +200,7 @@ module Lookbook
198
200
  {
199
201
  file_path: @preview&.full_path,
200
202
  line_number: 0,
201
- source_code: @example&.source
203
+ source_code: @target&.source
202
204
  }
203
205
  elsif exception.is_a?(ActionView::Template::Error) & exception.message.include?("implements a reserved method")
204
206
  message_parts = exception.message.split("\n").first.split
@@ -6,7 +6,8 @@ module Lookbook
6
6
  render Lookbook::Icon::Component.new(name: name, **attrs)
7
7
  end
8
8
 
9
- def code(**attrs, &block)
9
+ def code(language = :html, **attrs, &block)
10
+ attrs[:language] = language
10
11
  render Lookbook::Code::Component.new(**attrs), &block
11
12
  end
12
13
 
@@ -29,7 +29,7 @@
29
29
  <% group.button icon: :code,
30
30
  tooltip: "Copy page embed code",
31
31
  copy: true do %>
32
- &lt;%= embed <%= @preview.preview_class %>, :<%= @example.name %>, params: <%= request.query_parameters.deep_symbolize_keys.to_s %> %&gt;
32
+ &lt;%= embed <%= @preview.preview_class %>, :<%= @target.name %>, params: <%= request.query_parameters.deep_symbolize_keys.to_s %> %&gt;
33
33
  <% end %>
34
34
  <% end %>
35
35
 
@@ -38,7 +38,7 @@
38
38
  "@click.stop": "startSpin(); $dispatch('viewport:reload'); stopSpin(500);" %>
39
39
 
40
40
  <% group.button icon: :external_link,
41
- href: lookbook_preview_path(@example.lookup_path, request.query_parameters),
41
+ href: lookbook_preview_path(@target.lookup_path, request.query_parameters),
42
42
  tooltip: "Open preview in new window",
43
43
  target: "_blank" %>
44
44
 
data/config/routes.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  Lookbook::Engine.routes.draw do
2
- if Lookbook.config.auto_refresh
2
+ if Lookbook::Engine.websocket?
3
3
  mount Lookbook::Engine.websocket => Lookbook.config.cable_mount_path
4
4
  end
5
5
 
@@ -11,6 +11,10 @@ module Lookbook
11
11
  name.underscore
12
12
  end
13
13
 
14
+ def rel_path
15
+ Pathname.new("#{path}.rb")
16
+ end
17
+
14
18
  def full_path
15
19
  Pathname.new("#{Lookbook.config.components_path}/#{path}.rb")
16
20
  end
@@ -1,7 +1,6 @@
1
1
  require "view_component"
2
2
  require "action_cable/engine"
3
3
  require "listen"
4
- require "rake"
5
4
 
6
5
  module Lookbook
7
6
  autoload :Config, "lookbook/config"
@@ -107,7 +106,7 @@ module Lookbook
107
106
  end
108
107
  else
109
108
  # Fallback for older Rails versions - don't start listeners if running in a rake task.
110
- unless File.basename($0) == "rake" || Rake.application.top_level_tasks.any?
109
+ unless Lookbook::Engine.prevent_listening?
111
110
  init_listeners
112
111
  end
113
112
  end
@@ -127,69 +126,75 @@ module Lookbook
127
126
  Lookbook::Engine.run_hooks(:after_initialize)
128
127
  end
129
128
 
130
- def init_listeners
131
- return unless config.lookbook.listen == true
132
- Listen.logger = Lookbook.logger
133
- Lookbook.logger.info "Initializing listeners"
134
-
135
- preview_listener = Listen.to(
136
- *config.lookbook.listen_paths,
137
- only: /\.(#{config.lookbook.listen_extensions.join("|")})$/,
138
- force_polling: config.lookbook.listen_use_polling
139
- ) do |modified, added, removed|
140
- changes = {modified: modified, added: added, removed: removed}
141
- begin
142
- Lookbook::Engine.parser.parse
143
- rescue
144
- end
145
- Lookbook::Preview.clear_cache
146
- Lookbook::Engine.reload_ui(changes)
147
- Lookbook::Engine.run_hooks(:after_change, changes)
148
- end
149
- Lookbook::Engine.register_listener(preview_listener)
150
-
151
- page_listener = Listen.to(
152
- *config.lookbook.page_paths,
153
- only: /\.(html.*|md.*)$/,
154
- force_polling: config.lookbook.listen_use_polling
155
- ) do |modified, added, removed|
156
- changes = {modified: modified, added: added, removed: removed}
157
- Lookbook::Engine.reload_ui(changes)
158
- Lookbook::Engine.run_hooks(:after_change, changes)
159
- end
160
- Lookbook::Engine.register_listener(page_listener)
161
- end
162
-
163
129
  at_exit do
164
130
  if Lookbook::Engine.listeners.any?
165
131
  Lookbook.logger.debug "Stopping listeners"
166
- Lookbook::Engine.listeners.each { |listener| listener.stop }
132
+ Lookbook::Engine.stop_listeners
167
133
  end
168
134
  Lookbook::Engine.run_hooks(:before_exit)
169
135
  end
170
136
 
171
137
  class << self
138
+ def init_listeners
139
+ config = Lookbook.config
140
+ return unless config.listen == true
141
+ Listen.logger = Lookbook.logger
142
+
143
+ preview_listener = Listen.to(
144
+ *config.listen_paths,
145
+ only: /\.(#{config.listen_extensions.join("|")})$/,
146
+ force_polling: config.listen_use_polling
147
+ ) do |modified, added, removed|
148
+ changes = {modified: modified, added: added, removed: removed}
149
+ begin
150
+ parser.parse
151
+ rescue
152
+ end
153
+ Lookbook::Preview.clear_cache
154
+ reload_ui(changes)
155
+ run_hooks(:after_change, changes)
156
+ end
157
+ register_listener(preview_listener)
158
+
159
+ page_listener = Listen.to(
160
+ *config.page_paths,
161
+ only: /\.(html.*|md.*)$/,
162
+ force_polling: config.listen_use_polling
163
+ ) do |modified, added, removed|
164
+ changes = {modified: modified, added: added, removed: removed}
165
+ reload_ui(changes)
166
+ run_hooks(:after_change, changes)
167
+ end
168
+ register_listener(page_listener)
169
+ end
170
+
172
171
  def websocket
172
+ config = Lookbook.config
173
173
  return @websocket unless @websocket.nil?
174
- if config.lookbook.auto_refresh
175
- cable = ActionCable::Server::Configuration.new
176
- cable.cable = {adapter: "async"}.with_indifferent_access
177
- cable.mount_path = config.lookbook.cable_mount_path
178
- cable.connection_class = -> { Lookbook::Connection }
179
- cable.logger = config.lookbook.cable_logger
180
-
181
- @websocket ||= if Rails.version.to_f >= 6.0
182
- ActionCable::Server::Base.new(config: cable)
183
- else
184
- ws = ActionCable::Server::Base.new
185
- ws.config = cable
186
- ws
187
- end
174
+ return unless config.auto_refresh == true && !Rails.env.test?
175
+ Lookbook.logger.info "Initializing websocket"
176
+
177
+ cable = ActionCable::Server::Configuration.new
178
+ cable.cable = {adapter: "async"}.with_indifferent_access
179
+ cable.mount_path = config.cable_mount_path
180
+ cable.connection_class = -> { Lookbook::Connection }
181
+ cable.logger = config.cable_logger
182
+
183
+ @websocket ||= if Gem::Version.new(Rails.version) >= Gem::Version.new(6.0)
184
+ ActionCable::Server::Base.new(config: cable)
185
+ else
186
+ ws = ActionCable::Server::Base.new
187
+ ws.config = cable
188
+ ws
188
189
  end
189
190
  end
190
191
 
191
192
  def websocket_mount_path
192
- "#{mounted_path}#{config.lookbook.cable_mount_path}" if websocket
193
+ "#{mounted_path}#{config.lookbook.cable_mount_path}" if websocket?
194
+ end
195
+
196
+ def websocket?
197
+ websocket.present?
193
198
  end
194
199
 
195
200
  def mounted_path
@@ -222,6 +227,10 @@ module Lookbook
222
227
  @listeners ||= []
223
228
  end
224
229
 
230
+ def stop_listeners
231
+ listeners.each { |listener| listener.stop }
232
+ end
233
+
225
234
  def run_hooks(event_name, *args)
226
235
  config.lookbook.hooks[event_name].each do |hook|
227
236
  hook.call(Lookbook, *args)
@@ -232,6 +241,18 @@ module Lookbook
232
241
  websocket&.broadcast("reload", changed)
233
242
  end
234
243
 
244
+ def prevent_listening?
245
+ Rails.env.test? || running_in_rake_task?
246
+ end
247
+
248
+ def running_in_rake_task?
249
+ if defined?(Rake) && Rake.respond_to?(:application)
250
+ File.basename($0) == "rake" || Rake.application.top_level_tasks.any?
251
+ else
252
+ false
253
+ end
254
+ end
255
+
235
256
  attr_reader :preview_controller
236
257
  end
237
258
  end
data/lib/lookbook/page.rb CHANGED
@@ -13,7 +13,7 @@ module Lookbook
13
13
  :data
14
14
  ]
15
15
 
16
- attr_reader :errors
16
+ attr_reader :errors, :rel_path
17
17
  attr_accessor :sections
18
18
 
19
19
  def initialize(path, base_path)
@@ -23,8 +23,8 @@ module Lookbook
23
23
  @errors = []
24
24
  @sections = []
25
25
  @page_name = remove_position_prefix(path_name)
26
- rel_path = @pathname.relative_path_from(@base_path)
27
- page_path = rel_path.dirname.to_s == "." ? @page_name : "#{rel_path.dirname}/#{@page_name}"
26
+ @rel_path = @pathname.relative_path_from(@base_path)
27
+ page_path = @rel_path.dirname.to_s == "." ? @page_name : "#{@rel_path.dirname}/#{@page_name}"
28
28
  super(page_path)
29
29
  end
30
30
 
@@ -33,7 +33,7 @@ module Lookbook
33
33
  end
34
34
 
35
35
  def full_path
36
- Rails.root.join(@pathname.to_s)
36
+ Pathname.new Rails.root.join(@pathname.to_s)
37
37
  end
38
38
 
39
39
  def name
@@ -61,11 +61,15 @@ module Lookbook
61
61
  examples.first
62
62
  end
63
63
 
64
+ def rel_path
65
+ "#{name.underscore}.rb"
66
+ end
67
+
64
68
  def full_path
65
69
  base_path = Array(Lookbook.config.preview_paths).detect do |preview_path|
66
- Dir["#{preview_path}/#{name.underscore}.rb"].first
70
+ Dir["#{preview_path}/#{rel_path}"].first
67
71
  end
68
- Pathname.new(Dir["#{base_path}/#{name.underscore}.rb"].first)
72
+ Pathname.new(Dir["#{base_path}/#{rel_path}"].first)
69
73
  end
70
74
 
71
75
  def url_path
@@ -1,3 +1,3 @@
1
1
  module Lookbook
2
- VERSION = "1.0.1"
2
+ VERSION = "1.0.4"
3
3
  end