phlex_kit 0.6.1 → 0.7.0

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: 74f3d49a1a6adfab950d193db75d0cce12c02308c10fe69566d7a62ea0a835e3
4
- data.tar.gz: 0b673ba98ab594e4f2783a32c83b792e849605cd43fb1033d2bd258dece4c789
3
+ metadata.gz: 924514c45499b5f5d021cc5ec5416246c38ccfc0cb40bef9f65a9592e12960b3
4
+ data.tar.gz: 9531c44809a4b586547c41a45e2274acf24618436f10ca6d54f368f975ad199e
5
5
  SHA512:
6
- metadata.gz: d0e680e98ac74f15fa085a2828e7aa86041d67fa58ec82dd07d9f2912bc06c063ef58b5fcdcba5c44b037cc7b4070b01869b891da449ad8bcbb9ce4eb62facf4
7
- data.tar.gz: ddea978e8b26eaf08dcb373df2c59bec15405f0c043ca349c8c6f6e1c20194f75712281d526f70bc0fc234fcb2aeb41a79f42386182494a6a597af3bb9868fe3
6
+ metadata.gz: edbe03d8c7b0eafca03b08f4da7e28b0f220be45e3725e18fcc82972d9737341180be65617bcfee479d67a150e3876da29551bf39a46d52459b9a0f794d1672f
7
+ data.tar.gz: a25b1d74ac3d5cfb12dfd0f72a20bf1fcf92b115a7f25602cb62dfd0c19c77987db2ee02ee6fd4efd97548306b75d70e188eea2c56bbb4564cb2503d41f592bb
@@ -20,6 +20,16 @@
20
20
  position-try-fallbacks: flip-block;
21
21
  }
22
22
  .pk-dropdown-menu-content-up { position-area: block-start span-inline-end; margin: 0 0 4px; }
23
+ .pk-dropdown-menu-content-right {
24
+ position-area: inline-end span-block-end;
25
+ margin: 0 0 0 4px;
26
+ position-try-fallbacks: flip-inline;
27
+ }
28
+ .pk-dropdown-menu-content-left {
29
+ position-area: inline-start span-block-end;
30
+ margin: 0 4px 0 0;
31
+ position-try-fallbacks: flip-inline;
32
+ }
23
33
  .pk-dropdown-menu-viewport {
24
34
  min-width: 10rem;
25
35
  border-radius: calc(var(--pk-radius) - 2px);
@@ -1,9 +1,12 @@
1
1
  module PhlexKit
2
2
  # The dropdown panel — a native [popover=manual] the trigger toggles,
3
3
  # anchor-positioned with viewport-edge flipping. `side:` is :bottom
4
- # (default, opens below) or :top (opens above — for triggers near the bottom of
5
- # the viewport, e.g. the sidebar footer). See dropdown_menu.rb.
4
+ # (default, opens below), :top (opens above — for triggers near the bottom
5
+ # of the viewport, e.g. the sidebar footer), :right or :left (opens beside
6
+ # the trigger — shadcn's side prop). See dropdown_menu.rb.
6
7
  class DropdownMenuContent < BaseComponent
8
+ SIDES = { bottom: nil, top: "pk-dropdown-menu-content-up", left: "pk-dropdown-menu-content-left", right: "pk-dropdown-menu-content-right" }.freeze
9
+
7
10
  def initialize(side: :bottom, **attrs)
8
11
  @side = side.to_sym
9
12
  @attrs = attrs
@@ -18,7 +21,7 @@ module PhlexKit
18
21
  private
19
22
 
20
23
  def wrapper_classes
21
- [ "pk-dropdown-menu-content", ("pk-dropdown-menu-content-up" if @side == :top) ].compact.join(" ")
24
+ [ "pk-dropdown-menu-content", fetch_option(SIDES, @side, :side) ].compact.join(" ")
22
25
  end
23
26
  end
24
27
  end
@@ -18,6 +18,10 @@ export default class extends Controller {
18
18
  this.openMenu = null
19
19
  }
20
20
 
21
+ disconnect() {
22
+ clearTimeout(this.graceTimer)
23
+ }
24
+
21
25
  toggle(e) {
22
26
  const menu = e.currentTarget.closest("[data-phlex-kit--menubar-target=\"menu\"]")
23
27
  this.openMenu === menu ? this.close() : this.show(menu, true)
@@ -26,11 +30,28 @@ export default class extends Controller {
26
30
  // Hover: switches between menus while one is open (menubar), or opens
27
31
  // directly when the bar declares data-hover-open (navigation menu).
28
32
  switch(e) {
33
+ clearTimeout(this.graceTimer)
29
34
  const menu = e.currentTarget.closest("[data-phlex-kit--menubar-target=\"menu\"]")
30
- if (this.element.dataset.hoverOpen !== undefined) return this.show(menu)
35
+ if (this.element.dataset.hoverOpen !== undefined) {
36
+ if (!menu || !this.panel(menu)) return this.closeSoon() // link, no panel
37
+ return this.show(menu)
38
+ }
39
+ if (!menu) return this.close()
31
40
  if (this.openMenu && this.openMenu !== menu) this.show(menu)
32
41
  }
33
42
 
43
+ // Hover closes go through a short grace period so a diagonal pointer path
44
+ // that clips a sibling link (or briefly exits the nav) on its way to the
45
+ // panel doesn't slam it shut; reaching the panel or a trigger cancels.
46
+ closeSoon() {
47
+ clearTimeout(this.graceTimer)
48
+ this.graceTimer = setTimeout(() => this.close(), 150)
49
+ }
50
+
51
+ cancelClose() {
52
+ clearTimeout(this.graceTimer)
53
+ }
54
+
34
55
  show(menu, focus = false) {
35
56
  if (this.openMenu !== menu) {
36
57
  this.close()
@@ -42,6 +63,7 @@ export default class extends Controller {
42
63
  }
43
64
 
44
65
  close(opts = {}) {
66
+ clearTimeout(this.graceTimer)
45
67
  const menu = this.openMenu
46
68
  if (!menu) return
47
69
  const panel = this.panel(menu)
@@ -15,7 +15,7 @@ module PhlexKit
15
15
  data: {
16
16
  controller: "phlex-kit--menubar",
17
17
  hover_open: true,
18
- action: "click@window->phlex-kit--menubar#onClickOutside keydown.esc->phlex-kit--menubar#close mouseleave->phlex-kit--menubar#close"
18
+ action: "click@window->phlex-kit--menubar#onClickOutside keydown.esc->phlex-kit--menubar#close mouseleave->phlex-kit--menubar#closeSoon"
19
19
  }
20
20
  }, @attrs), &)
21
21
  end
@@ -5,7 +5,7 @@ module PhlexKit
5
5
  def view_template(&)
6
6
  # No role="menu" here — the panel holds plain links, not menuitems
7
7
  # (Radix/shadcn ship no menu role on NavigationMenu content either).
8
- div(**mix({ class: "pk-navigation-menu-content", popover: "manual" }, @attrs), &)
8
+ div(**mix({ class: "pk-navigation-menu-content", popover: "manual", data: { action: "mouseenter->phlex-kit--menubar#cancelClose" } }, @attrs), &)
9
9
  end
10
10
  end
11
11
  end
@@ -1,5 +1,9 @@
1
1
  module PhlexKit
2
- # Plain link item (top-level or inside a panel). See navigation_menu.rb.
2
+ # Plain link item (top-level or inside a panel). Hover fires #switch like a
3
+ # trigger: for a TOP-LEVEL link the closest menu item has no panel, so an
4
+ # open sibling panel closes; for a link INSIDE a panel the closest item IS
5
+ # the open menu, so switch is a no-op and the panel stays. See
6
+ # navigation_menu.rb.
3
7
  class NavigationMenuLink < BaseComponent
4
8
  def initialize(href: "#", **attrs)
5
9
  @href = href
@@ -7,7 +11,7 @@ module PhlexKit
7
11
  end
8
12
 
9
13
  def view_template(&)
10
- a(**mix({ class: "pk-navigation-menu-link", href: @href }, @attrs), &)
14
+ a(**mix({ class: "pk-navigation-menu-link", href: @href, data: { action: "mouseenter->phlex-kit--menubar#switch" } }, @attrs), &)
11
15
  end
12
16
  end
13
17
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PhlexKit
4
- VERSION = "0.6.1"
4
+ VERSION = "0.7.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: phlex_kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Kennedy