lookbook 0.2.0 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +92 -111
- data/app/assets/lookbook/js/app.js +3 -1
- data/app/views/lookbook/layouts/app.html.erb +5 -3
- data/app/views/lookbook/partials/_preview.html.erb +1 -1
- data/config/routes.rb +3 -1
- data/lib/lookbook/engine.rb +6 -4
- data/lib/lookbook/preview.rb +3 -1
- data/lib/lookbook/version.rb +1 -1
- data/public/lookbook-assets/app.css +10 -12
- data/public/lookbook-assets/app.js +54 -25
- metadata +4 -5
- data/config/lookbook_cable.yml +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f643b8df09b68fb0e91d8dd522b186d8bcb8e58fa7883841a112a82a4ec81f8d
|
4
|
+
data.tar.gz: f97771056316f5e652a9850c2ac6495fb1c934135fada28af6557c7cd602e90a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4dc35a94c6173b687c903f098b5f0c05d8025c9171efa05ed0eb24993685c8495b7497f30df0f7d4550b2609f4dcbd0263624f8b1c9a7ed740bfd66dc48d288
|
7
|
+
data.tar.gz: 1f63d7ae4b684c46f89e0bfe683dbc83e0bf5daca16ced87c6061f0e7ea8c8da0c9131de71b9fd6dad7990211108fcad25d35ff5669b31b95eac78c6db70d48b
|
data/README.md
CHANGED
@@ -1,31 +1,35 @@
|
|
1
1
|
<div align="center">
|
2
|
-
|
2
|
+
<h1>👀 Lookbook 👀</h1>
|
3
3
|
|
4
|
-
|
4
|
+
<p>A native development UI for <a href="http://viewcomponent.org/">ViewComponent</a></p>
|
5
5
|
|
6
|
+
<div>
|
7
|
+
<a href="https://rubygems.org/gems/lookbook"><img src="https://badge.fury.io/rb/lookbook.svg" alt="Gem version">
|
8
|
+
<a href="https://github.com/testdouble/standard"><img src="https://img.shields.io/badge/code_style-standard-brightgreen.svg" alt="Ruby Style Guide">
|
9
|
+
<a href="https://github.com/prettier/prettier"><img src="https://img.shields.io/badge/code_style-prettier-ff69b4.svg" alt="Code style: Prettier">
|
10
|
+
</div>
|
6
11
|
</div>
|
7
12
|
|
8
13
|
---
|
9
14
|
|
10
|
-
Lookbook gives [ViewComponent](http://viewcomponent.org/)-based projects a _ready-to-go_ development UI for navigating, inspecting and interacting with component previews
|
15
|
+
**Lookbook gives [ViewComponent](http://viewcomponent.org/)-based projects a _ready-to-go_ development UI for navigating, inspecting and interacting with component previews.**
|
11
16
|
|
12
|
-
It uses (and extends) the native [ViewComponent preview functionality](https://viewcomponent.org/guide/previews.html)
|
17
|
+
It uses (and extends) the native [ViewComponent preview functionality](https://viewcomponent.org/guide/previews.html), so you don't need to learn a new DSL or create any extra files to get up and running.
|
13
18
|
|
14
19
|
Lookbook uses [RDoc/Yard-style comment tags](https://rubydoc.info/gems/yard/file/docs/Tags.md) to extend the capabilities of ViewComponent's previews whilst maintaining compatability with the standard preview class format, so you can add or remove Lookbook at any time without having to rework your code.
|
15
20
|
|
16
|
-
> ⚠️ **PLEASE NOTE!** Lookbook is very much a **work in progress** at the moment. There may be breaking changes on point-releases before a 1.0 version is ready. ⚠️
|
17
|
-
|
18
21
|
![Lookbook UI](.github/assets/lookbook_screenshot.png)
|
19
22
|
|
20
23
|
### Features
|
21
24
|
|
22
|
-
-
|
23
|
-
-
|
24
|
-
-
|
25
|
-
-
|
26
|
-
-
|
27
|
-
-
|
28
|
-
-
|
25
|
+
- Tree-style navigation menu
|
26
|
+
- Live nav search/filter
|
27
|
+
- Resizable preview window for responsive testing
|
28
|
+
- Highlighted preview source code and HTML output
|
29
|
+
- Add notes via comments in the preview file (markdown supported)
|
30
|
+
- Auto-updating UI when component or preview files are updated
|
31
|
+
- Supports 'hidden' previews and examples
|
32
|
+
- Works with standard the ViewComponent preview system
|
29
33
|
|
30
34
|
## Lookbook demo
|
31
35
|
|
@@ -35,27 +39,23 @@ The [demo app repo](https://github.com/allmarkedup/lookbook-demo) contains instr
|
|
35
39
|
|
36
40
|
## Installing
|
37
41
|
|
38
|
-
Lookbook is
|
39
|
-
|
40
|
-
If you wish to play with it in it's current state you can include it directly from Github using the instructions below.
|
42
|
+
> ⚠️ **Please note:** Lookbook is still in the early stages of development and has not yet been well tested across a wide range of Rails/ViewComponent versions and setups. If you run into any problems please [open an issue](issues) with as much detail as possible. Thanks! ⚠️
|
41
43
|
|
42
44
|
### 1. Add as a dependency
|
43
45
|
|
44
|
-
|
46
|
+
Add Lookbook to your `Gemfile` somewhere **after** the ViewComponent gem. For example:
|
45
47
|
|
46
48
|
```ruby
|
47
|
-
gem "
|
49
|
+
gem "view_component", require: "view_component/engine"
|
50
|
+
gem "lookbook"
|
48
51
|
```
|
49
52
|
|
50
|
-
This line should be placed <strong>below</strong> wherever you have specified the `view_component` gem.
|
51
|
-
|
52
53
|
### 2. Mount the Lookbook engine
|
53
54
|
|
54
55
|
You then need to mount the Lookbook engine (at a path of your choosing) in your `routes.rb` file:
|
55
56
|
|
56
57
|
```ruby
|
57
58
|
Rails.application.routes.draw do
|
58
|
-
# any other routes...
|
59
59
|
if Rails.env.development?
|
60
60
|
mount Lookbook::Engine, at: "/lookbook"
|
61
61
|
end
|
@@ -64,145 +64,116 @@ end
|
|
64
64
|
|
65
65
|
The `at` property determines the root URL that the Lookbook UI will be served at.
|
66
66
|
|
67
|
-
> If you would like to expose the Lookbook UI in production as well as in development, just remove the `if Rails.env.development?`
|
67
|
+
> If you would like to expose the Lookbook UI in production as well as in development, just remove the `if Rails.env.development?` condition from around the mount statement.
|
68
68
|
|
69
69
|
Then you can start your app as normal and navigate to `http://localhost:3000/lookbook` (or whatever mount path you specified) to view your component previews in the Lookbook UI.
|
70
70
|
|
71
71
|
## Usage
|
72
72
|
|
73
|
-
You don't need to do anything special to
|
73
|
+
You don't need to do anything special to see your ViewComponent previews and examples in Lookbook - just create them as normal and they'll automatically appear in the Lookbook UI. Preview templates, custom layouts and even bespoke [preview controllers](https://viewcomponent.org/guide/previews.html#configuring-preview-controller) should all work as you would expect.
|
74
74
|
|
75
|
-
|
75
|
+
> If you are new to ViewComponent development, checkout the ViewComponent [documentation](https://viewcomponent.org/guide/) on how to get started developing your components and [creating previews](https://viewcomponent.org/guide/previews.html).
|
76
76
|
|
77
|
-
|
77
|
+
### Annotating preview files
|
78
78
|
|
79
|
-
Lookbook
|
79
|
+
Lookbook parses [Yard-style comment tags](https://rubydoc.info/gems/yard/file/docs/Tags.md) in your preview classes to customise and extend the standard ViewComponent preview experience:
|
80
80
|
|
81
|
-
|
81
|
+
```ruby
|
82
|
+
# @label Basic Button
|
83
|
+
class ButtonComponentPreview < ViewComponent::Preview
|
82
84
|
|
83
|
-
|
85
|
+
# Primary button
|
86
|
+
# ---------------
|
87
|
+
# This is the button style you should use for most things.
|
88
|
+
#
|
89
|
+
# @label Primary
|
90
|
+
def default
|
91
|
+
render ButtonComponent.new do
|
92
|
+
"Click me"
|
93
|
+
end
|
94
|
+
end
|
84
95
|
|
85
|
-
|
96
|
+
# Secondary button
|
97
|
+
# ---------------
|
98
|
+
# This should be used for less important actions.
|
99
|
+
def secondary
|
100
|
+
render ButtonComponent.new(style: :secondary) do
|
101
|
+
"Click me"
|
102
|
+
end
|
103
|
+
end
|
86
104
|
|
87
|
-
|
88
|
-
#
|
89
|
-
#
|
90
|
-
|
91
|
-
# This is a method-level comment.
|
105
|
+
# Unicorn button
|
106
|
+
# ---------------
|
107
|
+
# This button style is still a **work in progress**.
|
108
|
+
#
|
92
109
|
# @hidden
|
93
|
-
def
|
110
|
+
def secondary
|
111
|
+
render ButtonComponent.new do
|
112
|
+
"Click me"
|
113
|
+
end
|
94
114
|
end
|
95
115
|
end
|
96
116
|
```
|
97
117
|
|
98
|
-
|
118
|
+
**Tags** are just strings identified by their `@` prefix - for example `@hidden`. Tags are always placed in a comment above the relevant preview class or example method.
|
99
119
|
|
100
|
-
|
120
|
+
The following Lookbook-specific tags are available for use:
|
101
121
|
|
102
|
-
|
122
|
+
#### `@label <text>`
|
103
123
|
|
104
|
-
|
124
|
+
Used to replace the auto-generated navigation label for the item with `<text>`.
|
105
125
|
|
106
|
-
|
126
|
+
> Available for preview classes & example methods.
|
107
127
|
|
108
128
|
```ruby
|
109
|
-
|
129
|
+
# @label Preview Label
|
130
|
+
class FooComponentPreview < ViewComponent::Preview
|
110
131
|
|
111
|
-
#
|
112
|
-
# Multi-line is just fine and **markdown** is supported too!
|
113
|
-
#
|
114
|
-
# It's a good place to put usage and implementation instructions
|
115
|
-
# for people browsing the component previews in the UI.
|
132
|
+
# @label Example Label
|
116
133
|
def default
|
117
|
-
render ButtonComponent.new(text: "Click me")
|
118
|
-
end
|
119
|
-
|
120
|
-
# Each preview example has it's own notes, extracted from the method comments.
|
121
|
-
def danger
|
122
|
-
render ButtonComponent.new(text: "Don't do it!", theme: :danger)
|
123
134
|
end
|
124
135
|
end
|
125
136
|
```
|
126
137
|
|
127
|
-
|
138
|
+
#### `@hidden`
|
128
139
|
|
129
|
-
|
140
|
+
Used to temporarily exclude an item from the Lookbook navigation. The item will still be accessible via it's URL.
|
130
141
|
|
131
|
-
|
142
|
+
Can be useful when a component (or a variant of a component) is still in development and is not ready to be shared with the wider team.
|
132
143
|
|
133
|
-
|
134
|
-
|
135
|
-
If you wish to override the automatic navigation label generation for a preview or example you can use the `@label` comment tag:
|
144
|
+
> Available for both preview classes & example methods.
|
136
145
|
|
137
146
|
```ruby
|
138
|
-
# @
|
139
|
-
class
|
147
|
+
# @hidden
|
148
|
+
class FooComponentPreview < ViewComponent::Preview
|
140
149
|
|
141
|
-
# @
|
142
|
-
def
|
150
|
+
# @hidden
|
151
|
+
def default
|
143
152
|
end
|
144
153
|
end
|
145
154
|
```
|
146
155
|
|
147
|
-
|
148
|
-
|
149
|
-
<img src=".github/assets/nav_labels.png" width="200">
|
150
|
-
|
151
|
-
#### Excluding previews and/or examples from the navigation
|
156
|
+
#### Adding notes
|
152
157
|
|
153
|
-
|
154
|
-
|
155
|
-
To **hide an entire preview** so that it no longer shows up in the , include the `@hidden` tag in a class comment:
|
158
|
+
All comment text other than tags will be treated as markdown and rendered in the **Notes** panel for that example in the Lookbook UI.
|
156
159
|
|
157
160
|
```ruby
|
158
161
|
# @hidden
|
159
|
-
class
|
160
|
-
# examples here....
|
161
|
-
end
|
162
|
-
```
|
162
|
+
class ProfileCardComponentPreview < ViewComponent::Preview
|
163
163
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
# Hidden Example
|
170
|
-
# ----------
|
171
|
-
# You won't see this in the nav!
|
172
|
-
#
|
173
|
-
# @hidden
|
174
|
-
def hidden_example
|
175
|
-
# ...
|
176
|
-
end
|
177
|
-
|
178
|
-
def a_visible_example
|
179
|
-
# ...
|
180
|
-
end
|
181
|
-
|
182
|
-
# @hidden
|
183
|
-
def another_hidden_example
|
184
|
-
# ...
|
164
|
+
# Profile Card
|
165
|
+
# ------------
|
166
|
+
# Use the default profile card component whenever you need to represent a user.
|
167
|
+
def default
|
185
168
|
end
|
186
169
|
end
|
187
170
|
```
|
188
171
|
|
189
|
-
|
190
|
-
|
191
|
-
Lookbook displays the source code of the current preview (or the contents of preview template, if one is being used), right underneath the rendered preview itself:
|
192
|
-
|
193
|
-
<img src=".github/assets/preview_source.png" width="400">
|
194
|
-
|
195
|
-
You can also inspect the HTML output of the rendered preview (without any of the layout cruft):
|
196
|
-
|
197
|
-
<img src=".github/assets/preview_output.png" width="400">
|
198
|
-
|
199
|
-
All code panels have a 'copy-to-clipboard' button at the top right of the panel, just click it to copy the un-highlighted code to your clipboard.
|
200
|
-
|
201
|
-
<img src=".github/assets/copy_to_clipboard.png" width="400">
|
172
|
+
<img src=".github/assets/preview_example_notes.png" width="400">
|
202
173
|
|
203
174
|
## Configuration
|
204
175
|
|
205
|
-
Lookbook
|
176
|
+
Lookbook will use the ViewComponent [configuration](https://viewcomponent.org/api.html#configuration) for your project to find and render your previews so you generally you won't need to configure anything separately.
|
206
177
|
|
207
178
|
However the following Lookbook-specific config options are also available:
|
208
179
|
|
@@ -222,12 +193,22 @@ If you wish to add additional paths to listen for changes in, you can use the `l
|
|
222
193
|
config.lookbook.listen_paths << Rails.root.join('app/other/directory')
|
223
194
|
```
|
224
195
|
|
196
|
+
## Troubleshooting
|
197
|
+
|
198
|
+
#### Blank preview window
|
199
|
+
|
200
|
+
Certain setups (for example when using `Rack::LiveReload`) can cause an issue with the way that the preview iframe displays the rendered component preview (i.e. using the `srcdoc` attribute to avoid extra requests).
|
201
|
+
|
202
|
+
If you are seeing a blank preview window, but the source and output tabs are both displaying code as expected, you can disable the use of the `srcdoc` attribute using the following configuration option:
|
203
|
+
|
204
|
+
```ruby
|
205
|
+
config.lookbook.preview_srcdoc = false
|
206
|
+
```
|
207
|
+
|
225
208
|
## Contributing
|
226
209
|
|
227
210
|
Lookbook is very much a small hobby/side project at the moment. I'd love to hear from anyone who is interested in contributing but I'm terrible at replying to emails or messages, so don't be surprised if I take forever to get back to you. It's not personal 😜
|
228
211
|
|
229
|
-
However, I'm a frontend developer - not a Rails dev - so any thoughts, advice or PRs on how to improve the codebase will be always much appreciated. 🍻
|
230
|
-
|
231
212
|
### Developing on a local version of Lookbook
|
232
213
|
|
233
214
|
The quickest way to get a development version of Lookbook up and running is to use the [lookbook-demo](https://github.com/allmarkedup/lookbook-demo) app and link it to a local version of the Lookbook gem:
|
@@ -8,9 +8,11 @@
|
|
8
8
|
<link href="/lookbook-assets/app.css" rel="stylesheet">
|
9
9
|
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>👀</text></svg>">
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
<% if config.auto_refresh %>
|
12
|
+
<script>
|
13
|
+
window.SOCKET_PATH = "/lookbook/cable";
|
14
|
+
</script>
|
15
|
+
<% end %>
|
14
16
|
<script src="/lookbook-assets/app.js" defer></script>
|
15
17
|
|
16
18
|
<title><%= [@example&.label, @preview&.label, "Lookbook"].compact.join(" :: ") %></title>
|
@@ -2,7 +2,7 @@
|
|
2
2
|
<div class="h-full relative mx-auto bg-white" x-data="preview" :style="`width: ${$store.preview.width}`">
|
3
3
|
<iframe
|
4
4
|
src="<%= url_for lookbook.preview_path %>"
|
5
|
-
srcdoc="<%== @preview_srcdoc %>"
|
5
|
+
<% if config.preview_srcdoc %>srcdoc="<%== @preview_srcdoc %>"<% end %>
|
6
6
|
frameborder="0"
|
7
7
|
class="h-full w-full border-l border-gray-300 pr-4 -mx-px"
|
8
8
|
x-data="sizeObserver"
|
data/config/routes.rb
CHANGED
data/lib/lookbook/engine.rb
CHANGED
@@ -28,6 +28,7 @@ module Lookbook
|
|
28
28
|
options.preview_paths += vc_options.preview_paths
|
29
29
|
|
30
30
|
options.preview_controller = vc_options.preview_controller if options.preview_controller.nil?
|
31
|
+
options.preview_srcdoc = true if options.preview_srcdoc.nil?
|
31
32
|
|
32
33
|
options.listen_paths = options.listen_paths.map(&:to_s)
|
33
34
|
options.listen_paths += options.preview_paths
|
@@ -35,10 +36,11 @@ module Lookbook
|
|
35
36
|
end
|
36
37
|
|
37
38
|
initializer "lookbook.cable.config" do |app|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
if app.config.lookbook.auto_refresh
|
40
|
+
Lookbook::Engine.cable.cable = {adapter: "async"}.with_indifferent_access
|
41
|
+
Lookbook::Engine.cable.mount_path = "/cable"
|
42
|
+
Lookbook::Engine.cable.connection_class = -> { Lookbook::Connection }
|
43
|
+
end
|
42
44
|
end
|
43
45
|
|
44
46
|
initializer "lookbook.cable.logger" do
|
data/lib/lookbook/preview.rb
CHANGED
@@ -17,7 +17,9 @@ module Lookbook
|
|
17
17
|
|
18
18
|
def lookbook_examples
|
19
19
|
return @lookbook_examples if @lookbook_examples.present?
|
20
|
-
|
20
|
+
public_methods = public_instance_methods(false)
|
21
|
+
public_method_objects = code_object.meths.filter { |m| public_methods.include?(m.name) }
|
22
|
+
examples = public_method_objects.map { |m| PreviewExample.new(m.name.to_s, self) }
|
21
23
|
examples.reject!(&:hidden?)
|
22
24
|
@lookbook_examples ||= Lookbook.config.sort_examples ? examples.sort_by(&:label) : examples
|
23
25
|
end
|
data/lib/lookbook/version.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
/*! tailwindcss v2.2.
|
1
|
+
/*! tailwindcss v2.2.7 | MIT License | https://tailwindcss.com */
|
2
2
|
|
3
3
|
/*! modern-normalize v1.1.0 | MIT License | https://github.com/sindresorhus/modern-normalize */
|
4
4
|
|
@@ -575,6 +575,14 @@ video {
|
|
575
575
|
height: auto;
|
576
576
|
}
|
577
577
|
|
578
|
+
/**
|
579
|
+
* Ensure the default browser behavior of the `hidden` attribute.
|
580
|
+
*/
|
581
|
+
|
582
|
+
[hidden] {
|
583
|
+
display: none;
|
584
|
+
}
|
585
|
+
|
578
586
|
*, ::before, ::after {
|
579
587
|
--tw-translate-x: 0;
|
580
588
|
--tw-translate-y: 0;
|
@@ -586,13 +594,13 @@ video {
|
|
586
594
|
--tw-transform: translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
587
595
|
--tw-border-opacity: 1;
|
588
596
|
border-color: rgba(229, 231, 235, var(--tw-border-opacity));
|
589
|
-
--tw-shadow: 0 0 #0000;
|
590
597
|
--tw-ring-inset: var(--tw-empty,/*!*/ /*!*/);
|
591
598
|
--tw-ring-offset-width: 0px;
|
592
599
|
--tw-ring-offset-color: #fff;
|
593
600
|
--tw-ring-color: rgba(59, 130, 246, 0.5);
|
594
601
|
--tw-ring-offset-shadow: 0 0 #0000;
|
595
602
|
--tw-ring-shadow: 0 0 #0000;
|
603
|
+
--tw-shadow: 0 0 #0000;
|
596
604
|
--tw-blur: var(--tw-empty,/*!*/ /*!*/);
|
597
605
|
--tw-brightness: var(--tw-empty,/*!*/ /*!*/);
|
598
606
|
--tw-contrast: var(--tw-empty,/*!*/ /*!*/);
|
@@ -603,16 +611,6 @@ video {
|
|
603
611
|
--tw-sepia: var(--tw-empty,/*!*/ /*!*/);
|
604
612
|
--tw-drop-shadow: var(--tw-empty,/*!*/ /*!*/);
|
605
613
|
--tw-filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
606
|
-
--tw-backdrop-blur: var(--tw-empty,/*!*/ /*!*/);
|
607
|
-
--tw-backdrop-brightness: var(--tw-empty,/*!*/ /*!*/);
|
608
|
-
--tw-backdrop-contrast: var(--tw-empty,/*!*/ /*!*/);
|
609
|
-
--tw-backdrop-grayscale: var(--tw-empty,/*!*/ /*!*/);
|
610
|
-
--tw-backdrop-hue-rotate: var(--tw-empty,/*!*/ /*!*/);
|
611
|
-
--tw-backdrop-invert: var(--tw-empty,/*!*/ /*!*/);
|
612
|
-
--tw-backdrop-opacity: var(--tw-empty,/*!*/ /*!*/);
|
613
|
-
--tw-backdrop-saturate: var(--tw-empty,/*!*/ /*!*/);
|
614
|
-
--tw-backdrop-sepia: var(--tw-empty,/*!*/ /*!*/);
|
615
|
-
--tw-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
|
616
614
|
}
|
617
615
|
|
618
616
|
[type='text'],[type='email'],[type='url'],[type='password'],[type='number'],[type='date'],[type='datetime-local'],[type='month'],[type='search'],[type='tel'],[type='time'],[type='week'],[multiple],textarea,select {
|
@@ -2294,12 +2294,17 @@ Expression: "${expression}"
|
|
2294
2294
|
});
|
2295
2295
|
}
|
2296
2296
|
var isDeferringHandlers = false;
|
2297
|
-
var
|
2297
|
+
var directiveHandlerStacks = new Map();
|
2298
|
+
var currentHandlerStackKey = Symbol();
|
2298
2299
|
function deferHandlingDirectives(callback) {
|
2299
2300
|
isDeferringHandlers = true;
|
2301
|
+
let key = Symbol();
|
2302
|
+
currentHandlerStackKey = key;
|
2303
|
+
directiveHandlerStacks.set(key, []);
|
2300
2304
|
let flushHandlers = () => {
|
2301
|
-
while (
|
2302
|
-
|
2305
|
+
while (directiveHandlerStacks.get(key).length)
|
2306
|
+
directiveHandlerStacks.get(key).shift()();
|
2307
|
+
directiveHandlerStacks.delete(key);
|
2303
2308
|
};
|
2304
2309
|
let stopDeferring = () => {
|
2305
2310
|
isDeferringHandlers = false;
|
@@ -2330,7 +2335,7 @@ Expression: "${expression}"
|
|
2330
2335
|
return;
|
2331
2336
|
handler3.inline && handler3.inline(el, directive2, utilities);
|
2332
2337
|
handler3 = handler3.bind(handler3, el, directive2, utilities);
|
2333
|
-
isDeferringHandlers ?
|
2338
|
+
isDeferringHandlers ? directiveHandlerStacks.get(currentHandlerStackKey).push(handler3) : handler3();
|
2334
2339
|
};
|
2335
2340
|
fullHandler.runCleanups = doCleanup;
|
2336
2341
|
return fullHandler;
|
@@ -2449,7 +2454,7 @@ Expression: "${expression}"
|
|
2449
2454
|
onAttributesAdded((el, attrs) => {
|
2450
2455
|
directives(el, attrs).forEach((handle) => handle());
|
2451
2456
|
});
|
2452
|
-
let outNestedComponents = (el) => !closestRoot(el.
|
2457
|
+
let outNestedComponents = (el) => !closestRoot(el.parentElement);
|
2453
2458
|
Array.from(document.querySelectorAll(allSelectors())).filter(outNestedComponents).forEach((el) => {
|
2454
2459
|
initTree(el);
|
2455
2460
|
});
|
@@ -2470,6 +2475,8 @@ Expression: "${expression}"
|
|
2470
2475
|
initSelectorCallbacks.push(selectorCallback);
|
2471
2476
|
}
|
2472
2477
|
function closestRoot(el) {
|
2478
|
+
if (!el)
|
2479
|
+
return;
|
2473
2480
|
if (rootSelectors().some((selector) => el.matches(selector)))
|
2474
2481
|
return el;
|
2475
2482
|
if (!el.parentElement)
|
@@ -2576,7 +2583,7 @@ Expression: "${expression}"
|
|
2576
2583
|
get raw() {
|
2577
2584
|
return raw;
|
2578
2585
|
},
|
2579
|
-
version: "3.2.
|
2586
|
+
version: "3.2.4",
|
2580
2587
|
disableEffectScheduling,
|
2581
2588
|
setReactivityEngine,
|
2582
2589
|
addRootSelector,
|
@@ -2678,7 +2685,7 @@ Expression: "${expression}"
|
|
2678
2685
|
let previousStyles = {};
|
2679
2686
|
Object.entries(value).forEach(([key, value2]) => {
|
2680
2687
|
previousStyles[key] = el.style[key];
|
2681
|
-
el.style
|
2688
|
+
el.style.setProperty(kebabCase(key), value2);
|
2682
2689
|
});
|
2683
2690
|
setTimeout(() => {
|
2684
2691
|
if (el.style.length === 0) {
|
@@ -2696,6 +2703,9 @@ Expression: "${expression}"
|
|
2696
2703
|
el.setAttribute("style", cache);
|
2697
2704
|
};
|
2698
2705
|
}
|
2706
|
+
function kebabCase(subject) {
|
2707
|
+
return subject.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
2708
|
+
}
|
2699
2709
|
function once(callback, fallback = () => {
|
2700
2710
|
}) {
|
2701
2711
|
let called = false;
|
@@ -3113,6 +3123,8 @@ Expression: "${expression}"
|
|
3113
3123
|
let handler3 = (e) => callback(e);
|
3114
3124
|
let options = {};
|
3115
3125
|
let wrapHandler = (callback2, wrapper) => (e) => wrapper(callback2, e);
|
3126
|
+
if (modifiers.includes("dot"))
|
3127
|
+
event = dotSyntax(event);
|
3116
3128
|
if (modifiers.includes("camel"))
|
3117
3129
|
event = camelCase2(event);
|
3118
3130
|
if (modifiers.includes("passive"))
|
@@ -3174,6 +3186,9 @@ Expression: "${expression}"
|
|
3174
3186
|
listenerTarget.removeEventListener(event, handler3, options);
|
3175
3187
|
};
|
3176
3188
|
}
|
3189
|
+
function dotSyntax(subject) {
|
3190
|
+
return subject.replace(/-/g, ".");
|
3191
|
+
}
|
3177
3192
|
function camelCase2(subject) {
|
3178
3193
|
return subject.toLowerCase().replace(/-(\w)/g, (match, char) => char.toUpperCase());
|
3179
3194
|
}
|
@@ -3203,7 +3218,7 @@ Expression: "${expression}"
|
|
3203
3218
|
function isNumeric(subject) {
|
3204
3219
|
return !Array.isArray(subject) && !isNaN(subject);
|
3205
3220
|
}
|
3206
|
-
function
|
3221
|
+
function kebabCase2(subject) {
|
3207
3222
|
return subject.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[_\s]/, "-").toLowerCase();
|
3208
3223
|
}
|
3209
3224
|
function isKeyEvent(event) {
|
@@ -3219,7 +3234,7 @@ Expression: "${expression}"
|
|
3219
3234
|
}
|
3220
3235
|
if (keyModifiers.length === 0)
|
3221
3236
|
return false;
|
3222
|
-
if (keyModifiers.length === 1 &&
|
3237
|
+
if (keyModifiers.length === 1 && keyToModifiers(e.key).includes(keyModifiers[0]))
|
3223
3238
|
return false;
|
3224
3239
|
const systemKeyModifiers = ["ctrl", "shift", "alt", "meta", "cmd", "super"];
|
3225
3240
|
const selectedSystemKeyModifiers = systemKeyModifiers.filter((modifier) => keyModifiers.includes(modifier));
|
@@ -3231,22 +3246,33 @@ Expression: "${expression}"
|
|
3231
3246
|
return e[`${modifier}Key`];
|
3232
3247
|
});
|
3233
3248
|
if (activelyPressedKeyModifiers.length === selectedSystemKeyModifiers.length) {
|
3234
|
-
if (
|
3249
|
+
if (keyToModifiers(e.key).includes(keyModifiers[0]))
|
3235
3250
|
return false;
|
3236
3251
|
}
|
3237
3252
|
}
|
3238
3253
|
return true;
|
3239
3254
|
}
|
3240
|
-
function
|
3241
|
-
|
3242
|
-
|
3243
|
-
|
3244
|
-
|
3245
|
-
|
3246
|
-
|
3247
|
-
|
3248
|
-
|
3249
|
-
|
3255
|
+
function keyToModifiers(key) {
|
3256
|
+
if (!key)
|
3257
|
+
return [];
|
3258
|
+
key = kebabCase2(key);
|
3259
|
+
let modifierToKeyMap = {
|
3260
|
+
ctrl: "control",
|
3261
|
+
slash: "/",
|
3262
|
+
space: "-",
|
3263
|
+
spacebar: "-",
|
3264
|
+
cmd: "meta",
|
3265
|
+
esc: "escape",
|
3266
|
+
up: "arrow-up",
|
3267
|
+
down: "arrow-down",
|
3268
|
+
left: "arrow-left",
|
3269
|
+
right: "arrow-right"
|
3270
|
+
};
|
3271
|
+
modifierToKeyMap[key] = key;
|
3272
|
+
return Object.keys(modifierToKeyMap).map((modifier) => {
|
3273
|
+
if (modifierToKeyMap[modifier] === key)
|
3274
|
+
return modifier;
|
3275
|
+
}).filter((modifier) => modifier);
|
3250
3276
|
}
|
3251
3277
|
directive("model", (el, { modifiers, expression }, { effect: effect3, cleanup: cleanup2 }) => {
|
3252
3278
|
let evaluate2 = evaluateLater(el, expression);
|
@@ -3287,7 +3313,7 @@ Expression: "${expression}"
|
|
3287
3313
|
return (event, currentValue) => {
|
3288
3314
|
return mutateDom(() => {
|
3289
3315
|
if (event instanceof CustomEvent && event.detail !== void 0) {
|
3290
|
-
return event.detail;
|
3316
|
+
return event.detail || event.target.value;
|
3291
3317
|
} else if (el.type === "checkbox") {
|
3292
3318
|
if (Array.isArray(currentValue)) {
|
3293
3319
|
let newValue = modifiers.includes("number") ? safeParseNumber(event.target.value) : event.target.value;
|
@@ -3383,11 +3409,10 @@ Expression: "${expression}"
|
|
3383
3409
|
let reactiveData = reactive(data2);
|
3384
3410
|
initInterceptors(reactiveData);
|
3385
3411
|
let undo = addScopeToNode(el, reactiveData);
|
3386
|
-
|
3387
|
-
reactiveData["init"]();
|
3412
|
+
reactiveData["init"] && evaluate(el, reactiveData["init"]);
|
3388
3413
|
cleanup2(() => {
|
3389
3414
|
undo();
|
3390
|
-
reactiveData["destroy"] && reactiveData["destroy"]
|
3415
|
+
reactiveData["destroy"] && evaluate(el, reactiveData["destroy"]);
|
3391
3416
|
});
|
3392
3417
|
}));
|
3393
3418
|
directive("show", (el, { modifiers, expression }, { effect: effect3 }) => {
|
@@ -3444,6 +3469,8 @@ Expression: "${expression}"
|
|
3444
3469
|
if (isNumeric3(items) && items >= 0) {
|
3445
3470
|
items = Array.from(Array(items).keys(), (i) => i + 1);
|
3446
3471
|
}
|
3472
|
+
if (items === void 0)
|
3473
|
+
items = [];
|
3447
3474
|
let lookup = el._x_lookup;
|
3448
3475
|
let prevKeys = el._x_prevKeys;
|
3449
3476
|
let scopes = [];
|
@@ -7687,6 +7714,8 @@ Expression: "${expression}"
|
|
7687
7714
|
active: "source"
|
7688
7715
|
});
|
7689
7716
|
window.Alpine = module_default;
|
7690
|
-
|
7717
|
+
if (window.SOCKET_PATH) {
|
7718
|
+
reloader_default(window.SOCKET_PATH).start();
|
7719
|
+
}
|
7691
7720
|
module_default.start();
|
7692
7721
|
})();
|
metadata
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lookbook
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Perkins
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-09-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '6.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '6.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
@@ -200,7 +200,6 @@ files:
|
|
200
200
|
- app/views/lookbook/partials/nav/_label.html.erb
|
201
201
|
- app/views/lookbook/partials/nav/_nav.html.erb
|
202
202
|
- app/views/lookbook/partials/nav/_preview.html.erb
|
203
|
-
- config/lookbook_cable.yml
|
204
203
|
- config/routes.rb
|
205
204
|
- lib/lookbook.rb
|
206
205
|
- lib/lookbook/collection.rb
|