lookbook 0.3.4 → 0.4.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 64f02e35ce90b1e27249752c3ea536ead68b7f6dba3a6bb0991dff8f29f63d92
4
- data.tar.gz: effca06a618749eb6be51880929f417d0de03fe180d60e3df026065a7d0718ee
3
+ metadata.gz: 870ef6a17d84bca0a9fbbc421e27c2d6d682965d96c646f44d3db817e5a5e4f2
4
+ data.tar.gz: 669ce3b709792be5bdf46ac806efdca269d694349e74f759b0997cbbb456792e
5
5
  SHA512:
6
- metadata.gz: 3323004e8ea85985c687adfe184b0519b3b168676df1640cdb5ada335ffef304a1266e6ad239e62968261e2c043c98b23589dd28ed3913e22c620500fc76cdde
7
- data.tar.gz: a60ed3e4b295875fcac660f560d75dc4ac9ecff3cf26a410c30837326c84e26e8e2cea4ad183879ee94049836ab68fb81b3d59c0aab6c081d239744184cfc374
6
+ metadata.gz: b0293806f0d57b130c07ae84b5d30fad2625df0cbf2477303d924dddfd42ece6e49b10f15fc0b395fa65adfca3de3ab1096e72565a175bdab14df2af1ba57050
7
+ data.tar.gz: 2e5ad4ca7957d2684dc367b3a7d89d9922024cfc01cdbcd2567d30b830fe891b815924d64f5b7048783efd42736f41924354255f847850498fd596ba1c25e977
data/README.md CHANGED
@@ -16,19 +16,17 @@
16
16
 
17
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.
18
18
 
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.
19
+ Lookbook uses [RDoc/Yard-style comment tags](#annotating-preview-files) 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.
20
20
 
21
21
  ![Lookbook UI](.github/assets/lookbook_screenshot.png)
22
22
 
23
23
  ### Features
24
24
 
25
- - Tree-style navigation menu
26
- - Live nav search/filter
25
+ - Tree-style navigation menu with live search/filter
27
26
  - Resizable preview window for responsive testing
28
27
  - Highlighted preview source code and HTML output
29
- - Add notes via comments in the preview file (markdown supported)
30
28
  - Auto-updating UI when component or preview files are updated _(Rails v6.0+ only)_
31
- - Hide, group and rename preview examples using comment tags
29
+ - Use comment tag annotations for granular customisation of the preview experience
32
30
  - Fully compatible with standard the ViewComponent preview system
33
31
 
34
32
  ## Lookbook demo
@@ -39,8 +37,6 @@ The [demo app repo](https://github.com/allmarkedup/lookbook-demo) contains instr
39
37
 
40
38
  ## Installing
41
39
 
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! ⚠️
43
-
44
40
  ### 1. Add as a dependency
45
41
 
46
42
  Add Lookbook to your `Gemfile` somewhere **after** the ViewComponent gem. For example:
@@ -74,12 +70,13 @@ You don't need to do anything special to see your ViewComponent previews and exa
74
70
 
75
71
  > 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
72
 
77
- ### Annotating preview files
73
+ ## Annotating preview files
78
74
 
79
75
  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
76
 
81
77
  ```ruby
82
78
  # @label Basic Button
79
+ # @display bg_color: "#fff"
83
80
  class ButtonComponentPreview < ViewComponent::Preview
84
81
 
85
82
  # Primary button
@@ -93,11 +90,13 @@ class ButtonComponentPreview < ViewComponent::Preview
93
90
  end
94
91
  end
95
92
 
96
- # Secondary button
93
+ # Inverted button
97
94
  # ---------------
98
- # This should be used for less important actions.
95
+ # For light-on-dark screens
96
+ #
97
+ # @display bg_color: "#000"
99
98
  def secondary
100
- render ButtonComponent.new(style: :secondary) do
99
+ render ButtonComponent.new(style: :inverted) do
101
100
  "Click me"
102
101
  end
103
102
  end
@@ -142,7 +141,12 @@ end
142
141
 
143
142
  The following Lookbook-specific tags are available for use:
144
143
 
145
- #### `@label <text>`
144
+ * `@label <label>` -[Customise navigation labels](#-label-text)
145
+ * `@hidden` - [Prevent items displaying in the navigation](#-hidden)
146
+ * `@display <key>:<value>` - [Specify params to pass into the preview template](#-display-key-value)
147
+ * `@!group <name> ... @!endgroup` - [Render examples in a group on the same page](#-group-name--endgroup)
148
+
149
+ ### 🔖 `@label <text>`
146
150
 
147
151
  Used to replace the auto-generated navigation label for the item with `<text>`.
148
152
 
@@ -158,7 +162,7 @@ class FooComponentPreview < ViewComponent::Preview
158
162
  end
159
163
  ```
160
164
 
161
- #### `@hidden`
165
+ ### 🔖 `@hidden`
162
166
 
163
167
  Used to temporarily exclude an item from the Lookbook navigation. The item will still be accessible via it's URL.
164
168
 
@@ -176,7 +180,91 @@ class FooComponentPreview < ViewComponent::Preview
176
180
  end
177
181
  ```
178
182
 
179
- #### `@!group <name> ... @!endgroup`
183
+ ### 🔖 `@display <key>: <value>`
184
+
185
+ The `@display` tag lets you pass custom parameters to your preview layout so that the component preview can be customised on a per-example basis.
186
+
187
+ ```ruby
188
+ # @display bg_color: "#eee"
189
+ class FooComponentPreview < ViewComponent::Preview
190
+
191
+ # @display max_width: "500px"
192
+ # @display wrapper: true
193
+ def default
194
+ end
195
+ end
196
+ ```
197
+
198
+ The `@display` tag can be applied at the preview (class) or at the example (method) level, and takes the following format:
199
+
200
+ ```ruby
201
+ # @display <key>: <value>
202
+ ```
203
+
204
+ - `<key>` must be a valid Ruby hash key name, without quotes or spaces
205
+ - `<value>` must be a valid JSON-parsable value. It can be a string (surrounded by **double** quotes), a boolean or an integer.
206
+
207
+ > [See below for some examples](#some-display-value-examples) of valid and invalid `@display` values.
208
+
209
+ These display parameters can then be accessed via the `params` hash in your preview layout using `params[:lookbook][:display][<key>]`:
210
+
211
+ ```html
212
+ <!DOCTYPE html>
213
+ <html style="background-color: <%= params[:lookbook][:display][:bg_color] %>">
214
+ <head>
215
+ <title>Preview Layout</title>
216
+ </head>
217
+ <body>
218
+ <div style="max-width: <%= params[:lookbook][:display][:max_width] || '100%' %>">
219
+ <% if params[:lookbook][:display][:wrapper] == true %>
220
+ <div class="wrapper"><%= yield %></div>
221
+ <% else %>
222
+ <%= yield %>
223
+ <% end %>
224
+ </div>
225
+ </body>
226
+ </html>
227
+ ```
228
+
229
+ > By default ViewComponent will use your default application layout for displaying the rendered example. However it's often better to create a seperate layout that you can customise and use specifically for previewing your components. See the ViewComponent [preview docs](https://viewcomponent.org/guide/previews.html) for instructions on how to set that up.
230
+
231
+ Any `@display` params set at the preview (class) level with be merged with those set on individual example methods.
232
+
233
+ #### Global display params
234
+
235
+ Global (fallback) display params can be defined via a configuration option:
236
+
237
+ ```ruby
238
+ # config/application.rb
239
+ config.lookbook.preview_display_params = {
240
+ bg_color: "#fff",
241
+ max_width: "100%"
242
+ }
243
+ ```
244
+
245
+ Globally defined display params will be available to all previews. Any preview or example-level `@display` values with the same name will take precedence and override a globally-set one.
246
+
247
+ #### Some `@display` value examples:
248
+
249
+ Valid:
250
+
251
+ ```ruby
252
+ # @display body_classes: "bg-red border border-4 border-green"
253
+ # @display wrap_in_container: true
254
+ # @display emojis_to_show: 4
255
+ # @display page_title: "Special example title"
256
+ ```
257
+
258
+ Invalid:
259
+
260
+ ```ruby
261
+ # @display body_classes: 'bg-red border border-4 border-green' [❌ single quotes]
262
+ # @display wrap_in_container: should_wrap [❌ unquoted string, perhaps trying to call a method]
263
+ # @display page title: "Special example title" [❌ space in key]
264
+ # @display bg_color: #fff [❌ colors need quotes around them, it's not CSS!]
265
+ ```
266
+
267
+ ### 🔖 `@!group <name> ... @!endgroup`
180
268
 
181
269
  For smaller components, it can often make sense to render a set of preview examples in a single window, rather than representing them as individual items in the navigation which can start to look a bit cluttered.
182
270
 
@@ -222,7 +310,7 @@ The example above would display the `Sizes` examples grouped together on a singl
222
310
 
223
311
  You can have as many groups as you like within a single preview class, but each example can only belong to one group.
224
312
 
225
- #### Adding notes
313
+ ### Adding notes
226
314
 
227
315
  All comment text other than tags will be treated as markdown and rendered in the **Notes** panel for that example in the Lookbook UI.
228
316
 
@@ -14,6 +14,17 @@ export default function navNode() {
14
14
  ? Array.from(this.$refs.items.querySelectorAll(":scope > li"))
15
15
  : [];
16
16
  },
17
+ navigateToFirstChild() {
18
+ if (this.open()) {
19
+ const child = this.firstVisibleChild();
20
+ if (child) {
21
+ const link = child.querySelector(":scope > a.nav-link");
22
+ if (link) {
23
+ this.navigate(link.getAttribute("href"));
24
+ }
25
+ }
26
+ }
27
+ },
17
28
  filter() {
18
29
  this.hidden = true;
19
30
  this.getChildren().forEach((child) => {
@@ -27,5 +38,12 @@ export default function navNode() {
27
38
  toggle() {
28
39
  this.$store.nav.open[this.id] = !this.$store.nav.open[this.id];
29
40
  },
41
+ firstVisibleChild() {
42
+ return this.getChildren().find((child) => {
43
+ return child._x_dataStack
44
+ ? child._x_dataStack[0].hidden === false
45
+ : false;
46
+ });
47
+ },
30
48
  };
31
49
  }
@@ -95,14 +95,29 @@ module Lookbook
95
95
  html: preview_controller.render_example_to_string(@preview, example.name)
96
96
  }
97
97
  end
98
+ set_params
98
99
  joined = render_to_string "lookbook/preview_group", locals: {examples: examples}, layout: nil
99
- preview_controller.render_in_layout_to_string(joined, @preview.lookbook_layout)
100
+ preview_controller.render_in_layout_to_string(joined, @preview.lookbook_layout || current_layout)
100
101
  else
101
- preview_controller.request.params[:path] = "#{@preview.preview_name}/#{@example.name}".chomp("/")
102
+ set_params(@example)
103
+ preview_controller.params[:path] = "#{@preview.preview_name}/#{@example.name}".chomp("/")
102
104
  preview_controller.process(:previews)
103
105
  end
104
106
  end
105
107
 
108
+ def set_params(example = nil)
109
+ example_params = @preview.lookbook_display_params.deep_merge(example ? example.lookbook_display_params : {})
110
+ preview_controller.params.merge!({
111
+ lookbook: {
112
+ display: Lookbook.config.preview_display_params.deep_merge(example_params)
113
+ }
114
+ })
115
+ end
116
+
117
+ def current_layout
118
+ preview_controller.send :_layout, preview_controller.lookup_context, [:html]
119
+ end
120
+
106
121
  def assign_inspector
107
122
  @inspector = {
108
123
  panes: {
@@ -5,7 +5,7 @@ label ||= leaf.label
5
5
  %>
6
6
  <li x-data="navLeaf" :class="{hidden}" x-init="matchers = <%= leaf.matchers.to_json %>; path = '<%= path %>'; setActive()" @popstate.window="setActive">
7
7
  <a href="<%= path %>"
8
- class="pr-3 py-[5px] flex items-center w-full group transition hover:bg-gray-200 hover:bg-opacity-50"
8
+ class="nav-link pr-3 py-[5px] flex items-center w-full group transition hover:bg-gray-200 hover:bg-opacity-50"
9
9
  style="<%= nav_padding_style(depth) %>"
10
10
  :class="{'!bg-indigo-100':active}"
11
11
  @click.stop.prevent="navigate"
@@ -8,7 +8,7 @@
8
8
  <svg class="feather h-3.5 w-3.5 mr-1.5 flex-none text-indigo-500">
9
9
  <use xlink:href="/lookbook-assets/feather-sprite.svg#<%= node.type == :preview ? 'layers' : 'folder' %>" />
10
10
  </svg>
11
- <div class="truncate w-full whitespace-nowrap text-left <%= "font-bold" if node.type == :preview %>" @click.stop="toggle(); if (open()) { <%= "navigate('#{path}')" if defined?(path) %>}">
11
+ <div class="truncate w-full whitespace-nowrap text-left <%= "font-bold" if node.type == :preview %>" @click.stop="toggle(); navigateToFirstChild();">
12
12
  <%= node.label %>
13
13
  </div>
14
14
  </div>
@@ -30,6 +30,7 @@ module Lookbook
30
30
 
31
31
  options.preview_controller = vc_options.preview_controller if options.preview_controller.nil?
32
32
  options.preview_srcdoc = true if options.preview_srcdoc.nil?
33
+ options.preview_display_params ||= {}
33
34
 
34
35
  options.listen_paths = options.listen_paths.map(&:to_s)
35
36
  options.listen_paths += options.preview_paths
@@ -27,6 +27,7 @@ module Lookbook
27
27
  def define_tags
28
28
  YARD::Tags::Library.define_tag("Hidden status", :hidden)
29
29
  YARD::Tags::Library.define_tag("Label", :label)
30
+ YARD::Tags::Library.define_tag("Display", :display)
30
31
  end
31
32
  end
32
33
  end
@@ -20,6 +20,23 @@ module Lookbook
20
20
  code_object&.group
21
21
  end
22
22
 
23
+ def lookbook_display_params
24
+ display_params = {}
25
+ if code_object&.tags(:display).present?
26
+ code_object.tags(:display).each do |tag|
27
+ parts = tag.text.match(/^\s?([^:]*)\s?:\s?(.*)\s?$/)
28
+ if parts.present?
29
+ begin
30
+ display_params[parts[1]] = JSON.parse parts[2]
31
+ rescue JSON::ParserError => err
32
+ Rails.logger.error("\n👀 [Lookbook] Invalid JSON in @display tag.\n👀 [Lookbook] (#{err.to_s})\n")
33
+ end
34
+ end
35
+ end
36
+ end
37
+ display_params
38
+ end
39
+
23
40
  # private
24
41
 
25
42
  def code_object
@@ -1,3 +1,3 @@
1
1
  module Lookbook
2
- VERSION = "0.3.4"
2
+ VERSION = "0.4.0.beta.1"
3
3
  end
@@ -1,4 +1,4 @@
1
- /*! tailwindcss v2.2.7 | MIT License | https://tailwindcss.com */
1
+ /*! tailwindcss v2.2.17 | MIT License | https://tailwindcss.com */
2
2
 
3
3
  /*! modern-normalize v1.1.0 | MIT License | https://github.com/sindresorhus/modern-normalize */
4
4
 
@@ -475,6 +475,18 @@ button,
475
475
  cursor: pointer;
476
476
  }
477
477
 
478
+ /**
479
+ * Override legacy focus reset from Normalize with modern Firefox focus styles.
480
+ *
481
+ * This is actually an improvement over the new defaults in Firefox in our testing,
482
+ * as it triggers the better focus styles even for links, which still use a dotted
483
+ * outline in Firefox by default.
484
+ */
485
+
486
+ :-moz-focusring {
487
+ outline: auto;
488
+ }
489
+
478
490
  table {
479
491
  border-collapse: collapse;
480
492
  }
@@ -627,6 +639,7 @@ video {
627
639
  padding-left: 0.75rem;
628
640
  font-size: 1rem;
629
641
  line-height: 1.5rem;
642
+ --tw-shadow: 0 0 #0000;
630
643
  }
631
644
 
632
645
  [type='text']:focus, [type='email']:focus, [type='url']:focus, [type='password']:focus, [type='number']:focus, [type='date']:focus, [type='datetime-local']:focus, [type='month']:focus, [type='search']:focus, [type='tel']:focus, [type='time']:focus, [type='week']:focus, [multiple]:focus, textarea:focus, select:focus {
@@ -638,7 +651,7 @@ video {
638
651
  --tw-ring-color: #2563eb;
639
652
  --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
640
653
  --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
641
- box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
654
+ box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
642
655
  border-color: #2563eb;
643
656
  }
644
657
 
@@ -706,6 +719,7 @@ select {
706
719
  background-color: #fff;
707
720
  border-color: #6b7280;
708
721
  border-width: 1px;
722
+ --tw-shadow: 0 0 #0000;
709
723
  }
710
724
 
711
725
  [type='checkbox'] {
@@ -725,7 +739,7 @@ select {
725
739
  --tw-ring-color: #2563eb;
726
740
  --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
727
741
  --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
728
- box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
742
+ box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
729
743
  }
730
744
 
731
745
  [type='checkbox']:checked,[type='radio']:checked {
@@ -2023,6 +2037,7 @@ pre[class*="language-"] {
2023
2037
  border-radius:4px;
2024
2038
  font-size:14px;
2025
2039
  line-height:1.4;
2040
+ white-space:normal;
2026
2041
  outline:0;
2027
2042
  transition-property:transform,visibility,opacity
2028
2043
  }
@@ -1,7 +1,9 @@
1
1
  (() => {
2
2
  var __create = Object.create;
3
3
  var __defProp = Object.defineProperty;
4
+ var __defProps = Object.defineProperties;
4
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
5
7
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
8
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
7
9
  var __getProtoOf = Object.getPrototypeOf;
@@ -19,6 +21,7 @@
19
21
  }
20
22
  return a;
21
23
  };
24
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
22
25
  var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
23
26
  var __commonJS = (cb, mod) => function __require() {
24
27
  return mod || (0, cb[Object.keys(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
@@ -710,7 +713,11 @@
710
713
  const type = (element.getAttribute("type") || "").toLowerCase();
711
714
  return name === "select" || name === "textarea" || name === "input" && type !== "submit" && type !== "reset" && type !== "checkbox" && type !== "radio" || element.isContentEditable;
712
715
  }
713
- function fireDeterminedAction(el) {
716
+ function fireDeterminedAction(el, path2) {
717
+ const delegateEvent = new CustomEvent("hotkey-fire", { cancelable: true, detail: { path: path2 } });
718
+ const cancelled = !el.dispatchEvent(delegateEvent);
719
+ if (cancelled)
720
+ return;
714
721
  if (isFormField(el)) {
715
722
  el.focus();
716
723
  } else {
@@ -728,15 +735,24 @@
728
735
  var elementsLeaves = new WeakMap();
729
736
  var currentTriePosition = hotkeyRadixTrie;
730
737
  var resetTriePositionTimer = null;
738
+ var path = [];
731
739
  function resetTriePosition() {
740
+ path = [];
732
741
  resetTriePositionTimer = null;
733
742
  currentTriePosition = hotkeyRadixTrie;
734
743
  }
735
744
  function keyDownHandler(event) {
736
745
  if (event.defaultPrevented)
737
746
  return;
738
- if (event.target instanceof Node && isFormField(event.target))
747
+ if (!(event.target instanceof Node))
739
748
  return;
749
+ if (isFormField(event.target)) {
750
+ const target = event.target;
751
+ if (!target.id)
752
+ return;
753
+ if (!target.ownerDocument.querySelector(`[data-hotkey-scope=${target.id}]`))
754
+ return;
755
+ }
740
756
  if (resetTriePositionTimer != null) {
741
757
  window.clearTimeout(resetTriePositionTimer);
742
758
  }
@@ -746,12 +762,26 @@
746
762
  resetTriePosition();
747
763
  return;
748
764
  }
765
+ path.push(hotkey(event));
749
766
  currentTriePosition = newTriePosition;
750
767
  if (newTriePosition instanceof Leaf) {
751
- fireDeterminedAction(newTriePosition.children[newTriePosition.children.length - 1]);
752
- event.preventDefault();
768
+ const target = event.target;
769
+ let shouldFire = false;
770
+ let elementToFire;
771
+ const formField = isFormField(target);
772
+ for (let i = newTriePosition.children.length - 1; i >= 0; i -= 1) {
773
+ elementToFire = newTriePosition.children[i];
774
+ const scope = elementToFire.getAttribute("data-hotkey-scope");
775
+ if (!formField && !scope || formField && target.id === scope) {
776
+ shouldFire = true;
777
+ break;
778
+ }
779
+ }
780
+ if (elementToFire && shouldFire) {
781
+ fireDeterminedAction(elementToFire, path);
782
+ event.preventDefault();
783
+ }
753
784
  resetTriePosition();
754
- return;
755
785
  }
756
786
  }
757
787
  function install(element, hotkey2) {
@@ -2108,8 +2138,10 @@
2108
2138
  if (!el._x_attributeCleanups)
2109
2139
  return;
2110
2140
  Object.entries(el._x_attributeCleanups).forEach(([name, value]) => {
2111
- (names === void 0 || names.includes(name)) && value.forEach((i) => i());
2112
- delete el._x_attributeCleanups[name];
2141
+ if (names === void 0 || names.includes(name)) {
2142
+ value.forEach((i) => i());
2143
+ delete el._x_attributeCleanups[name];
2144
+ }
2113
2145
  });
2114
2146
  }
2115
2147
  var observer = new MutationObserver(onMutate);
@@ -2119,6 +2151,7 @@
2119
2151
  currentlyObserving = true;
2120
2152
  }
2121
2153
  function stopObservingMutations() {
2154
+ flushObserver();
2122
2155
  observer.disconnect();
2123
2156
  currentlyObserving = false;
2124
2157
  }
@@ -2141,13 +2174,26 @@
2141
2174
  function mutateDom(callback) {
2142
2175
  if (!currentlyObserving)
2143
2176
  return callback();
2144
- flushObserver();
2145
2177
  stopObservingMutations();
2146
2178
  let result = callback();
2147
2179
  startObservingMutations();
2148
2180
  return result;
2149
2181
  }
2182
+ var isCollecting = false;
2183
+ var deferredMutations = [];
2184
+ function deferMutations() {
2185
+ isCollecting = true;
2186
+ }
2187
+ function flushAndStopDeferringMutations() {
2188
+ isCollecting = false;
2189
+ onMutate(deferredMutations);
2190
+ deferredMutations = [];
2191
+ }
2150
2192
  function onMutate(mutations) {
2193
+ if (isCollecting) {
2194
+ deferredMutations = deferredMutations.concat(mutations);
2195
+ return;
2196
+ }
2151
2197
  let addedNodes = [];
2152
2198
  let removedNodes = [];
2153
2199
  let addedAttributes = new Map();
@@ -2219,7 +2265,7 @@
2219
2265
  function closestDataStack(node) {
2220
2266
  if (node._x_dataStack)
2221
2267
  return node._x_dataStack;
2222
- if (node instanceof ShadowRoot) {
2268
+ if (typeof ShadowRoot === "function" && node instanceof ShadowRoot) {
2223
2269
  return closestDataStack(node.host);
2224
2270
  }
2225
2271
  if (!node.parentNode) {
@@ -2228,7 +2274,7 @@
2228
2274
  return closestDataStack(node.parentNode);
2229
2275
  }
2230
2276
  function mergeProxies(objects) {
2231
- return new Proxy({}, {
2277
+ let thisProxy = new Proxy({}, {
2232
2278
  ownKeys: () => {
2233
2279
  return Array.from(new Set(objects.flatMap((i) => Object.keys(i))));
2234
2280
  },
@@ -2236,7 +2282,31 @@
2236
2282
  return objects.some((obj) => obj.hasOwnProperty(name));
2237
2283
  },
2238
2284
  get: (target, name) => {
2239
- return (objects.find((obj) => obj.hasOwnProperty(name)) || {})[name];
2285
+ return (objects.find((obj) => {
2286
+ if (obj.hasOwnProperty(name)) {
2287
+ let descriptor = Object.getOwnPropertyDescriptor(obj, name);
2288
+ if (descriptor.get && descriptor.get._x_alreadyBound || descriptor.set && descriptor.set._x_alreadyBound) {
2289
+ return true;
2290
+ }
2291
+ if ((descriptor.get || descriptor.set) && descriptor.enumerable) {
2292
+ let getter = descriptor.get;
2293
+ let setter = descriptor.set;
2294
+ let property = descriptor;
2295
+ getter = getter && getter.bind(thisProxy);
2296
+ setter = setter && setter.bind(thisProxy);
2297
+ if (getter)
2298
+ getter._x_alreadyBound = true;
2299
+ if (setter)
2300
+ setter._x_alreadyBound = true;
2301
+ Object.defineProperty(obj, name, __spreadProps(__spreadValues({}, property), {
2302
+ get: getter,
2303
+ set: setter
2304
+ }));
2305
+ }
2306
+ return true;
2307
+ }
2308
+ return false;
2309
+ }) || {})[name];
2240
2310
  },
2241
2311
  set: (target, name, value) => {
2242
2312
  let closestObjectWithKey = objects.find((obj) => obj.hasOwnProperty(name));
@@ -2248,17 +2318,18 @@
2248
2318
  return true;
2249
2319
  }
2250
2320
  });
2321
+ return thisProxy;
2251
2322
  }
2252
2323
  function initInterceptors(data2) {
2253
2324
  let isObject = (val) => typeof val === "object" && !Array.isArray(val) && val !== null;
2254
2325
  let recurse = (obj, basePath = "") => {
2255
2326
  Object.entries(obj).forEach(([key, value]) => {
2256
- let path = basePath === "" ? key : `${basePath}.${key}`;
2327
+ let path2 = basePath === "" ? key : `${basePath}.${key}`;
2257
2328
  if (typeof value === "object" && value !== null && value._x_interceptor) {
2258
- obj[key] = value.initialize(data2, path, key);
2329
+ obj[key] = value.initialize(data2, path2, key);
2259
2330
  } else {
2260
2331
  if (isObject(value) && value !== obj && !(value instanceof Element)) {
2261
- recurse(value, path);
2332
+ recurse(value, path2);
2262
2333
  }
2263
2334
  }
2264
2335
  });
@@ -2270,18 +2341,18 @@
2270
2341
  let obj = {
2271
2342
  initialValue: void 0,
2272
2343
  _x_interceptor: true,
2273
- initialize(data2, path, key) {
2274
- return callback(this.initialValue, () => get(data2, path), (value) => set(data2, path, value), path, key);
2344
+ initialize(data2, path2, key) {
2345
+ return callback(this.initialValue, () => get(data2, path2), (value) => set(data2, path2, value), path2, key);
2275
2346
  }
2276
2347
  };
2277
2348
  mutateObj(obj);
2278
2349
  return (initialValue) => {
2279
2350
  if (typeof initialValue === "object" && initialValue !== null && initialValue._x_interceptor) {
2280
2351
  let initialize = obj.initialize.bind(obj);
2281
- obj.initialize = (data2, path, key) => {
2282
- let innerValue = initialValue.initialize(data2, path, key);
2352
+ obj.initialize = (data2, path2, key) => {
2353
+ let innerValue = initialValue.initialize(data2, path2, key);
2283
2354
  obj.initialValue = innerValue;
2284
- return initialize(data2, path, key);
2355
+ return initialize(data2, path2, key);
2285
2356
  };
2286
2357
  } else {
2287
2358
  obj.initialValue = initialValue;
@@ -2289,22 +2360,22 @@
2289
2360
  return obj;
2290
2361
  };
2291
2362
  }
2292
- function get(obj, path) {
2293
- return path.split(".").reduce((carry, segment) => carry[segment], obj);
2363
+ function get(obj, path2) {
2364
+ return path2.split(".").reduce((carry, segment) => carry[segment], obj);
2294
2365
  }
2295
- function set(obj, path, value) {
2296
- if (typeof path === "string")
2297
- path = path.split(".");
2298
- if (path.length === 1)
2299
- obj[path[0]] = value;
2300
- else if (path.length === 0)
2366
+ function set(obj, path2, value) {
2367
+ if (typeof path2 === "string")
2368
+ path2 = path2.split(".");
2369
+ if (path2.length === 1)
2370
+ obj[path2[0]] = value;
2371
+ else if (path2.length === 0)
2301
2372
  throw error;
2302
2373
  else {
2303
- if (obj[path[0]])
2304
- return set(obj[path[0]], path.slice(1), value);
2374
+ if (obj[path2[0]])
2375
+ return set(obj[path2[0]], path2.slice(1), value);
2305
2376
  else {
2306
- obj[path[0]] = {};
2307
- return set(obj[path[0]], path.slice(1), value);
2377
+ obj[path2[0]] = {};
2378
+ return set(obj[path2[0]], path2.slice(1), value);
2308
2379
  }
2309
2380
  }
2310
2381
  }
@@ -2425,6 +2496,9 @@ Expression: "${expression}"
2425
2496
  return getDirectiveHandler(el, directive2);
2426
2497
  });
2427
2498
  }
2499
+ function attributesOnly(attributes) {
2500
+ return Array.from(attributes).map(toTransformedAttributes()).filter((attr) => !outNonAlpineAttributes(attr));
2501
+ }
2428
2502
  var isDeferringHandlers = false;
2429
2503
  var directiveHandlerStacks = new Map();
2430
2504
  var currentHandlerStackKey = Symbol();
@@ -2478,7 +2552,8 @@ Expression: "${expression}"
2478
2552
  return { name, value };
2479
2553
  };
2480
2554
  var into = (i) => i;
2481
- function toTransformedAttributes(callback) {
2555
+ function toTransformedAttributes(callback = () => {
2556
+ }) {
2482
2557
  return ({ name, value }) => {
2483
2558
  let { name: newName, value: newValue } = attributeTransformers.reduce((carry, transform) => {
2484
2559
  return transform(carry);
@@ -2558,7 +2633,7 @@ Expression: "${expression}"
2558
2633
  isHolding = true;
2559
2634
  }
2560
2635
  function walk(el, callback) {
2561
- if (el instanceof ShadowRoot) {
2636
+ if (typeof ShadowRoot === "function" && el instanceof ShadowRoot) {
2562
2637
  Array.from(el.children).forEach((el2) => walk(el2, callback));
2563
2638
  return;
2564
2639
  }
@@ -2586,7 +2661,7 @@ Expression: "${expression}"
2586
2661
  onAttributesAdded((el, attrs) => {
2587
2662
  directives(el, attrs).forEach((handle) => handle());
2588
2663
  });
2589
- let outNestedComponents = (el) => !closestRoot(el.parentElement);
2664
+ let outNestedComponents = (el) => !closestRoot(el.parentElement, true);
2590
2665
  Array.from(document.querySelectorAll(allSelectors())).filter(outNestedComponents).forEach((el) => {
2591
2666
  initTree(el);
2592
2667
  });
@@ -2606,14 +2681,15 @@ Expression: "${expression}"
2606
2681
  function addInitSelector(selectorCallback) {
2607
2682
  initSelectorCallbacks.push(selectorCallback);
2608
2683
  }
2609
- function closestRoot(el) {
2684
+ function closestRoot(el, includeInitSelectors = false) {
2610
2685
  if (!el)
2611
2686
  return;
2612
- if (rootSelectors().some((selector) => el.matches(selector)))
2687
+ const selectors = includeInitSelectors ? allSelectors() : rootSelectors();
2688
+ if (selectors.some((selector) => el.matches(selector)))
2613
2689
  return el;
2614
2690
  if (!el.parentElement)
2615
2691
  return;
2616
- return closestRoot(el.parentElement);
2692
+ return closestRoot(el.parentElement, includeInitSelectors);
2617
2693
  }
2618
2694
  function isRoot(el) {
2619
2695
  return rootSelectors().some((selector) => el.matches(selector));
@@ -2629,139 +2705,6 @@ Expression: "${expression}"
2629
2705
  function destroyTree(root) {
2630
2706
  walk(root, (el) => cleanupAttributes(el));
2631
2707
  }
2632
- function plugin(callback) {
2633
- callback(alpine_default);
2634
- }
2635
- var stores = {};
2636
- var isReactive = false;
2637
- function store(name, value) {
2638
- if (!isReactive) {
2639
- stores = reactive(stores);
2640
- isReactive = true;
2641
- }
2642
- if (value === void 0) {
2643
- return stores[name];
2644
- }
2645
- stores[name] = value;
2646
- if (typeof value === "object" && value !== null && value.hasOwnProperty("init") && typeof value.init === "function") {
2647
- stores[name].init();
2648
- }
2649
- }
2650
- function getStores() {
2651
- return stores;
2652
- }
2653
- var isCloning = false;
2654
- function skipDuringClone(callback) {
2655
- return (...args) => isCloning || callback(...args);
2656
- }
2657
- function clone(oldEl, newEl) {
2658
- newEl._x_dataStack = oldEl._x_dataStack;
2659
- isCloning = true;
2660
- dontRegisterReactiveSideEffects(() => {
2661
- cloneTree(newEl);
2662
- });
2663
- isCloning = false;
2664
- }
2665
- function cloneTree(el) {
2666
- let hasRunThroughFirstEl = false;
2667
- let shallowWalker = (el2, callback) => {
2668
- walk(el2, (el3, skip) => {
2669
- if (hasRunThroughFirstEl && isRoot(el3))
2670
- return skip();
2671
- hasRunThroughFirstEl = true;
2672
- callback(el3, skip);
2673
- });
2674
- };
2675
- initTree(el, shallowWalker);
2676
- }
2677
- function dontRegisterReactiveSideEffects(callback) {
2678
- let cache = effect;
2679
- overrideEffect((callback2, el) => {
2680
- let storedEffect = cache(callback2);
2681
- release(storedEffect);
2682
- return () => {
2683
- };
2684
- });
2685
- callback();
2686
- overrideEffect(cache);
2687
- }
2688
- var datas = {};
2689
- function data(name, callback) {
2690
- datas[name] = callback;
2691
- }
2692
- function injectDataProviders(obj, context) {
2693
- Object.entries(datas).forEach(([name, callback]) => {
2694
- Object.defineProperty(obj, name, {
2695
- get() {
2696
- return (...args) => {
2697
- return callback.bind(context)(...args);
2698
- };
2699
- },
2700
- enumerable: false
2701
- });
2702
- });
2703
- return obj;
2704
- }
2705
- var Alpine2 = {
2706
- get reactive() {
2707
- return reactive;
2708
- },
2709
- get release() {
2710
- return release;
2711
- },
2712
- get effect() {
2713
- return effect;
2714
- },
2715
- get raw() {
2716
- return raw;
2717
- },
2718
- version: "3.2.4",
2719
- disableEffectScheduling,
2720
- setReactivityEngine,
2721
- addRootSelector,
2722
- mapAttributes,
2723
- evaluateLater,
2724
- setEvaluator,
2725
- closestRoot,
2726
- interceptor,
2727
- mutateDom,
2728
- directive,
2729
- evaluate,
2730
- initTree,
2731
- nextTick,
2732
- prefix: setPrefix,
2733
- plugin,
2734
- magic,
2735
- store,
2736
- start,
2737
- clone,
2738
- data
2739
- };
2740
- var alpine_default = Alpine2;
2741
- var import_reactivity9 = __toModule2(require_reactivity());
2742
- magic("nextTick", () => nextTick);
2743
- magic("dispatch", (el) => dispatch.bind(dispatch, el));
2744
- magic("watch", (el) => (key, callback) => {
2745
- let evaluate2 = evaluateLater(el, key);
2746
- let firstTime = true;
2747
- let oldValue;
2748
- effect(() => evaluate2((value) => {
2749
- let div = document.createElement("div");
2750
- div.dataset.throwAway = value;
2751
- if (!firstTime) {
2752
- queueMicrotask(() => {
2753
- callback(value, oldValue);
2754
- oldValue = value;
2755
- });
2756
- } else {
2757
- oldValue = value;
2758
- }
2759
- firstTime = false;
2760
- }));
2761
- });
2762
- magic("store", getStores);
2763
- magic("refs", (el) => closestRoot(el)._x_refs || {});
2764
- magic("el", (el) => el);
2765
2708
  function setClasses(el, value) {
2766
2709
  if (Array.isArray(value)) {
2767
2710
  return setClassesFromString(el, value.join(" "));
@@ -2951,8 +2894,7 @@ Expression: "${expression}"
2951
2894
  transition(el, setFunction, {
2952
2895
  during: this.enter.during,
2953
2896
  start: this.enter.start,
2954
- end: this.enter.end,
2955
- entering: true
2897
+ end: this.enter.end
2956
2898
  }, before, after);
2957
2899
  },
2958
2900
  out(before = () => {
@@ -2961,14 +2903,15 @@ Expression: "${expression}"
2961
2903
  transition(el, setFunction, {
2962
2904
  during: this.leave.during,
2963
2905
  start: this.leave.start,
2964
- end: this.leave.end,
2965
- entering: false
2906
+ end: this.leave.end
2966
2907
  }, before, after);
2967
2908
  }
2968
2909
  };
2969
2910
  }
2970
2911
  window.Element.prototype._x_toggleAndCascadeWithTransitions = function(el, value, show, hide) {
2971
- let clickAwayCompatibleShow = () => requestAnimationFrame(show);
2912
+ let clickAwayCompatibleShow = () => {
2913
+ document.visibilityState === "visible" ? requestAnimationFrame(show) : setTimeout(show);
2914
+ };
2972
2915
  if (value) {
2973
2916
  el._x_transition ? el._x_transition.in(show) : clickAwayCompatibleShow();
2974
2917
  return;
@@ -3009,7 +2952,7 @@ Expression: "${expression}"
3009
2952
  return;
3010
2953
  return parent._x_hidePromise ? parent : closestHide(parent);
3011
2954
  }
3012
- function transition(el, setFunction, { during, start: start2, end, entering } = {}, before = () => {
2955
+ function transition(el, setFunction, { during, start: start2, end } = {}, before = () => {
3013
2956
  }, after = () => {
3014
2957
  }) {
3015
2958
  if (el._x_transitioning)
@@ -3037,9 +2980,9 @@ Expression: "${expression}"
3037
2980
  undoDuring();
3038
2981
  undoEnd();
3039
2982
  }
3040
- }, entering);
2983
+ });
3041
2984
  }
3042
- function performTransition(el, stages, entering) {
2985
+ function performTransition(el, stages) {
3043
2986
  let interrupted, reachedBefore, reachedEnd;
3044
2987
  let finish = once(() => {
3045
2988
  mutateDom(() => {
@@ -3068,8 +3011,7 @@ Expression: "${expression}"
3068
3011
  ;
3069
3012
  finish();
3070
3013
  }),
3071
- finish,
3072
- entering
3014
+ finish
3073
3015
  };
3074
3016
  mutateDom(() => {
3075
3017
  stages.start();
@@ -3121,6 +3063,184 @@ Expression: "${expression}"
3121
3063
  }
3122
3064
  return rawValue;
3123
3065
  }
3066
+ function debounce(func, wait) {
3067
+ var timeout;
3068
+ return function() {
3069
+ var context = this, args = arguments;
3070
+ var later = function() {
3071
+ timeout = null;
3072
+ func.apply(context, args);
3073
+ };
3074
+ clearTimeout(timeout);
3075
+ timeout = setTimeout(later, wait);
3076
+ };
3077
+ }
3078
+ function throttle(func, limit) {
3079
+ let inThrottle;
3080
+ return function() {
3081
+ let context = this, args = arguments;
3082
+ if (!inThrottle) {
3083
+ func.apply(context, args);
3084
+ inThrottle = true;
3085
+ setTimeout(() => inThrottle = false, limit);
3086
+ }
3087
+ };
3088
+ }
3089
+ function plugin(callback) {
3090
+ callback(alpine_default);
3091
+ }
3092
+ var stores = {};
3093
+ var isReactive = false;
3094
+ function store(name, value) {
3095
+ if (!isReactive) {
3096
+ stores = reactive(stores);
3097
+ isReactive = true;
3098
+ }
3099
+ if (value === void 0) {
3100
+ return stores[name];
3101
+ }
3102
+ stores[name] = value;
3103
+ if (typeof value === "object" && value !== null && value.hasOwnProperty("init") && typeof value.init === "function") {
3104
+ stores[name].init();
3105
+ }
3106
+ }
3107
+ function getStores() {
3108
+ return stores;
3109
+ }
3110
+ var isCloning = false;
3111
+ function skipDuringClone(callback) {
3112
+ return (...args) => isCloning || callback(...args);
3113
+ }
3114
+ function clone(oldEl, newEl) {
3115
+ newEl._x_dataStack = oldEl._x_dataStack;
3116
+ isCloning = true;
3117
+ dontRegisterReactiveSideEffects(() => {
3118
+ cloneTree(newEl);
3119
+ });
3120
+ isCloning = false;
3121
+ }
3122
+ function cloneTree(el) {
3123
+ let hasRunThroughFirstEl = false;
3124
+ let shallowWalker = (el2, callback) => {
3125
+ walk(el2, (el3, skip) => {
3126
+ if (hasRunThroughFirstEl && isRoot(el3))
3127
+ return skip();
3128
+ hasRunThroughFirstEl = true;
3129
+ callback(el3, skip);
3130
+ });
3131
+ };
3132
+ initTree(el, shallowWalker);
3133
+ }
3134
+ function dontRegisterReactiveSideEffects(callback) {
3135
+ let cache = effect;
3136
+ overrideEffect((callback2, el) => {
3137
+ let storedEffect = cache(callback2);
3138
+ release(storedEffect);
3139
+ return () => {
3140
+ };
3141
+ });
3142
+ callback();
3143
+ overrideEffect(cache);
3144
+ }
3145
+ var datas = {};
3146
+ function data(name, callback) {
3147
+ datas[name] = callback;
3148
+ }
3149
+ function injectDataProviders(obj, context) {
3150
+ Object.entries(datas).forEach(([name, callback]) => {
3151
+ Object.defineProperty(obj, name, {
3152
+ get() {
3153
+ return (...args) => {
3154
+ return callback.bind(context)(...args);
3155
+ };
3156
+ },
3157
+ enumerable: false
3158
+ });
3159
+ });
3160
+ return obj;
3161
+ }
3162
+ var Alpine2 = {
3163
+ get reactive() {
3164
+ return reactive;
3165
+ },
3166
+ get release() {
3167
+ return release;
3168
+ },
3169
+ get effect() {
3170
+ return effect;
3171
+ },
3172
+ get raw() {
3173
+ return raw;
3174
+ },
3175
+ version: "3.4.2",
3176
+ flushAndStopDeferringMutations,
3177
+ disableEffectScheduling,
3178
+ setReactivityEngine,
3179
+ addRootSelector,
3180
+ deferMutations,
3181
+ mapAttributes,
3182
+ evaluateLater,
3183
+ setEvaluator,
3184
+ closestRoot,
3185
+ interceptor,
3186
+ transition,
3187
+ setStyles,
3188
+ mutateDom,
3189
+ directive,
3190
+ throttle,
3191
+ debounce,
3192
+ evaluate,
3193
+ initTree,
3194
+ nextTick,
3195
+ prefix: setPrefix,
3196
+ plugin,
3197
+ magic,
3198
+ store,
3199
+ start,
3200
+ clone,
3201
+ data
3202
+ };
3203
+ var alpine_default = Alpine2;
3204
+ var import_reactivity9 = __toModule2(require_reactivity());
3205
+ magic("nextTick", () => nextTick);
3206
+ magic("dispatch", (el) => dispatch.bind(dispatch, el));
3207
+ magic("watch", (el) => (key, callback) => {
3208
+ let evaluate2 = evaluateLater(el, key);
3209
+ let firstTime = true;
3210
+ let oldValue;
3211
+ effect(() => evaluate2((value) => {
3212
+ let div = document.createElement("div");
3213
+ div.dataset.throwAway = value;
3214
+ if (!firstTime) {
3215
+ queueMicrotask(() => {
3216
+ callback(value, oldValue);
3217
+ oldValue = value;
3218
+ });
3219
+ } else {
3220
+ oldValue = value;
3221
+ }
3222
+ firstTime = false;
3223
+ }));
3224
+ });
3225
+ magic("store", getStores);
3226
+ magic("root", (el) => closestRoot(el));
3227
+ magic("refs", (el) => {
3228
+ if (el._x_refs_proxy)
3229
+ return el._x_refs_proxy;
3230
+ el._x_refs_proxy = mergeProxies(getArrayOfRefObject(el));
3231
+ return el._x_refs_proxy;
3232
+ });
3233
+ function getArrayOfRefObject(el) {
3234
+ let refObjects = [];
3235
+ let currentEl = el;
3236
+ while (currentEl) {
3237
+ if (currentEl._x_refs)
3238
+ refObjects.push(currentEl._x_refs);
3239
+ currentEl = currentEl.parentNode;
3240
+ }
3241
+ return refObjects;
3242
+ }
3243
+ magic("el", (el) => el);
3124
3244
  var handler = () => {
3125
3245
  };
3126
3246
  handler.inline = (el, { modifiers }, { cleanup: cleanup2 }) => {
@@ -3248,7 +3368,7 @@ Expression: "${expression}"
3248
3368
  return booleanAttributes.includes(attrName);
3249
3369
  }
3250
3370
  function attributeShouldntBePreservedIfFalsy(name) {
3251
- return !["aria-pressed", "aria-checked"].includes(name);
3371
+ return !["aria-pressed", "aria-checked", "aria-expanded"].includes(name);
3252
3372
  }
3253
3373
  function on(el, event, modifiers, callback) {
3254
3374
  let listenerTarget = el;
@@ -3261,6 +3381,8 @@ Expression: "${expression}"
3261
3381
  event = camelCase2(event);
3262
3382
  if (modifiers.includes("passive"))
3263
3383
  options.passive = true;
3384
+ if (modifiers.includes("capture"))
3385
+ options.capture = true;
3264
3386
  if (modifiers.includes("window"))
3265
3387
  listenerTarget = window;
3266
3388
  if (modifiers.includes("document"))
@@ -3300,12 +3422,12 @@ Expression: "${expression}"
3300
3422
  if (modifiers.includes("debounce")) {
3301
3423
  let nextModifier = modifiers[modifiers.indexOf("debounce") + 1] || "invalid-wait";
3302
3424
  let wait = isNumeric(nextModifier.split("ms")[0]) ? Number(nextModifier.split("ms")[0]) : 250;
3303
- handler3 = debounce(handler3, wait, this);
3425
+ handler3 = debounce(handler3, wait);
3304
3426
  }
3305
3427
  if (modifiers.includes("throttle")) {
3306
3428
  let nextModifier = modifiers[modifiers.indexOf("throttle") + 1] || "invalid-wait";
3307
3429
  let wait = isNumeric(nextModifier.split("ms")[0]) ? Number(nextModifier.split("ms")[0]) : 250;
3308
- handler3 = throttle(handler3, wait, this);
3430
+ handler3 = throttle(handler3, wait);
3309
3431
  }
3310
3432
  if (modifiers.includes("once")) {
3311
3433
  handler3 = wrapHandler(handler3, (next, e) => {
@@ -3324,29 +3446,6 @@ Expression: "${expression}"
3324
3446
  function camelCase2(subject) {
3325
3447
  return subject.toLowerCase().replace(/-(\w)/g, (match, char) => char.toUpperCase());
3326
3448
  }
3327
- function debounce(func, wait) {
3328
- var timeout;
3329
- return function() {
3330
- var context = this, args = arguments;
3331
- var later = function() {
3332
- timeout = null;
3333
- func.apply(context, args);
3334
- };
3335
- clearTimeout(timeout);
3336
- timeout = setTimeout(later, wait);
3337
- };
3338
- }
3339
- function throttle(func, limit) {
3340
- let inThrottle;
3341
- return function() {
3342
- let context = this, args = arguments;
3343
- if (!inThrottle) {
3344
- func.apply(context, args);
3345
- inThrottle = true;
3346
- setTimeout(() => inThrottle = false, limit);
3347
- }
3348
- };
3349
- }
3350
3449
  function isNumeric(subject) {
3351
3450
  return !Array.isArray(subject) && !isNaN(subject);
3352
3451
  }
@@ -3398,7 +3497,9 @@ Expression: "${expression}"
3398
3497
  up: "arrow-up",
3399
3498
  down: "arrow-down",
3400
3499
  left: "arrow-left",
3401
- right: "arrow-right"
3500
+ right: "arrow-right",
3501
+ period: ".",
3502
+ equal: "="
3402
3503
  };
3403
3504
  modifierToKeyMap[key] = key;
3404
3505
  return Object.keys(modifierToKeyMap).map((modifier) => {
@@ -3479,7 +3580,12 @@ Expression: "${expression}"
3479
3580
  }
3480
3581
  directive("cloak", (el) => queueMicrotask(() => mutateDom(() => el.removeAttribute(prefix("cloak")))));
3481
3582
  addInitSelector(() => `[${prefix("init")}]`);
3482
- directive("init", skipDuringClone((el, { expression }) => evaluate(el, expression, {}, false)));
3583
+ directive("init", skipDuringClone((el, { expression }) => {
3584
+ if (typeof expression === "string") {
3585
+ return !!expression.trim() && evaluate(el, expression, {}, false);
3586
+ }
3587
+ return evaluate(el, expression, {}, false);
3588
+ }));
3483
3589
  directive("text", (el, { expression }, { effect: effect3, evaluateLater: evaluateLater2 }) => {
3484
3590
  let evaluate2 = evaluateLater2(expression);
3485
3591
  effect3(() => {
@@ -3519,6 +3625,12 @@ Expression: "${expression}"
3519
3625
  cleanupRunners.pop()();
3520
3626
  getBindings((bindings) => {
3521
3627
  let attributes = Object.entries(bindings).map(([name, value]) => ({ name, value }));
3628
+ attributesOnly(attributes).forEach(({ name, value }, index2) => {
3629
+ attributes[index2] = {
3630
+ name: `x-bind:${name}`,
3631
+ value: `"${value}"`
3632
+ };
3633
+ });
3522
3634
  directives(el, attributes, original).map((handle) => {
3523
3635
  cleanupRunners.push(handle.runCleanups);
3524
3636
  handle();
@@ -3718,6 +3830,11 @@ Expression: "${expression}"
3718
3830
  names.forEach((name, i) => {
3719
3831
  scopeVariables[name] = item[i];
3720
3832
  });
3833
+ } else if (/^\{.*\}$/.test(iteratorNames.item) && !Array.isArray(item) && typeof item === "object") {
3834
+ let names = iteratorNames.item.replace("{", "").replace("}", "").split(",").map((i) => i.trim());
3835
+ names.forEach((name) => {
3836
+ scopeVariables[name] = item[name];
3837
+ });
3721
3838
  } else {
3722
3839
  scopeVariables[iteratorNames.item] = item;
3723
3840
  }
@@ -8374,11 +8491,11 @@ Expression: "${expression}"
8374
8491
  this.$dispatch("nav:updated");
8375
8492
  });
8376
8493
  },
8377
- navigate(path) {
8378
- if (path instanceof Event) {
8379
- path = path.currentTarget.href;
8494
+ navigate(path2) {
8495
+ if (path2 instanceof Event) {
8496
+ path2 = path2.currentTarget.href;
8380
8497
  }
8381
- history.pushState({}, null, path);
8498
+ history.pushState({}, null, path2);
8382
8499
  this.$dispatch("popstate");
8383
8500
  },
8384
8501
  focusFilter() {
@@ -8406,6 +8523,17 @@ Expression: "${expression}"
8406
8523
  getChildren() {
8407
8524
  return this.$refs.items ? Array.from(this.$refs.items.querySelectorAll(":scope > li")) : [];
8408
8525
  },
8526
+ navigateToFirstChild() {
8527
+ if (this.open()) {
8528
+ const child = this.firstVisibleChild();
8529
+ if (child) {
8530
+ const link = child.querySelector(":scope > a.nav-link");
8531
+ if (link) {
8532
+ this.navigate(link.getAttribute("href"));
8533
+ }
8534
+ }
8535
+ }
8536
+ },
8409
8537
  filter() {
8410
8538
  this.hidden = true;
8411
8539
  this.getChildren().forEach((child) => {
@@ -8418,6 +8546,11 @@ Expression: "${expression}"
8418
8546
  },
8419
8547
  toggle() {
8420
8548
  this.$store.nav.open[this.id] = !this.$store.nav.open[this.id];
8549
+ },
8550
+ firstVisibleChild() {
8551
+ return this.getChildren().find((child) => {
8552
+ return child._x_dataStack ? child._x_dataStack[0].hidden === false : false;
8553
+ });
8421
8554
  }
8422
8555
  };
8423
8556
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lookbook
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ version: 0.4.0.beta.1
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-10-18 00:00:00.000000000 Z
11
+ date: 2021-10-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -259,9 +259,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
259
259
  version: '0'
260
260
  required_rubygems_version: !ruby/object:Gem::Requirement
261
261
  requirements:
262
- - - ">="
262
+ - - ">"
263
263
  - !ruby/object:Gem::Version
264
- version: '0'
264
+ version: 1.3.1
265
265
  requirements: []
266
266
  rubygems_version: 3.1.2
267
267
  signing_key: