turbo_overlay 0.3.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.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +436 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +330 -0
  5. data/Rakefile +35 -0
  6. data/app/assets/stylesheets/turbo_overlay.css +234 -0
  7. data/app/javascript/turbo_overlay/dialog_utils.js +46 -0
  8. data/app/javascript/turbo_overlay/hint.js +670 -0
  9. data/app/javascript/turbo_overlay/history.js +184 -0
  10. data/app/javascript/turbo_overlay/index.js +53 -0
  11. data/app/javascript/turbo_overlay/options.js +152 -0
  12. data/app/javascript/turbo_overlay/overlay_controller.js +882 -0
  13. data/app/javascript/turbo_overlay/popover_position.js +64 -0
  14. data/app/javascript/turbo_overlay/setup.js +885 -0
  15. data/app/javascript/turbo_overlay/stack_controller.js +131 -0
  16. data/app/javascript/turbo_overlay/submit_close.js +49 -0
  17. data/app/javascript/turbo_overlay/visit.js +52 -0
  18. data/app/views/layouts/turbo_overlay/drawer.html.erb +5 -0
  19. data/app/views/layouts/turbo_overlay/hint.html.erb +10 -0
  20. data/app/views/layouts/turbo_overlay/modal.html.erb +5 -0
  21. data/app/views/layouts/turbo_overlay/popover.html.erb +5 -0
  22. data/app/views/turbo_overlay/_drawer.html.erb +49 -0
  23. data/app/views/turbo_overlay/_hint.html.erb +6 -0
  24. data/app/views/turbo_overlay/_loading.html.erb +12 -0
  25. data/app/views/turbo_overlay/_modal.html.erb +46 -0
  26. data/app/views/turbo_overlay/_popover.html.erb +54 -0
  27. data/config/importmap.rb +11 -0
  28. data/lib/generators/turbo_overlay/eject_generator.rb +115 -0
  29. data/lib/generators/turbo_overlay/install_generator.rb +443 -0
  30. data/lib/generators/turbo_overlay/templates/chrome/bootstrap3/_confirm.html.erb +13 -0
  31. data/lib/generators/turbo_overlay/templates/chrome/bootstrap3/_drawer.html.erb +50 -0
  32. data/lib/generators/turbo_overlay/templates/chrome/bootstrap3/_hint.html.erb +9 -0
  33. data/lib/generators/turbo_overlay/templates/chrome/bootstrap3/_loading.html.erb +9 -0
  34. data/lib/generators/turbo_overlay/templates/chrome/bootstrap3/_modal.html.erb +49 -0
  35. data/lib/generators/turbo_overlay/templates/chrome/bootstrap3/_popover.html.erb +54 -0
  36. data/lib/generators/turbo_overlay/templates/chrome/bootstrap5/_confirm.html.erb +13 -0
  37. data/lib/generators/turbo_overlay/templates/chrome/bootstrap5/_drawer.html.erb +55 -0
  38. data/lib/generators/turbo_overlay/templates/chrome/bootstrap5/_hint.html.erb +9 -0
  39. data/lib/generators/turbo_overlay/templates/chrome/bootstrap5/_loading.html.erb +9 -0
  40. data/lib/generators/turbo_overlay/templates/chrome/bootstrap5/_modal.html.erb +58 -0
  41. data/lib/generators/turbo_overlay/templates/chrome/bootstrap5/_popover.html.erb +53 -0
  42. data/lib/generators/turbo_overlay/templates/chrome/plain/_confirm.html.erb +14 -0
  43. data/lib/generators/turbo_overlay/templates/chrome/tailwind/_confirm.html.erb +17 -0
  44. data/lib/generators/turbo_overlay/templates/chrome/tailwind/_drawer.html.erb +55 -0
  45. data/lib/generators/turbo_overlay/templates/chrome/tailwind/_hint.html.erb +6 -0
  46. data/lib/generators/turbo_overlay/templates/chrome/tailwind/_loading.html.erb +9 -0
  47. data/lib/generators/turbo_overlay/templates/chrome/tailwind/_modal.html.erb +46 -0
  48. data/lib/generators/turbo_overlay/templates/chrome/tailwind/_popover.html.erb +54 -0
  49. data/lib/generators/turbo_overlay/templates/initializer.rb.tt +67 -0
  50. data/lib/turbo_overlay/configuration.rb +226 -0
  51. data/lib/turbo_overlay/controller.rb +405 -0
  52. data/lib/turbo_overlay/engine.rb +52 -0
  53. data/lib/turbo_overlay/helpers/stream_helper.rb +77 -0
  54. data/lib/turbo_overlay/helpers/view_helper.rb +651 -0
  55. data/lib/turbo_overlay/version.rb +3 -0
  56. data/lib/turbo_overlay.rb +20 -0
  57. metadata +161 -0
@@ -0,0 +1,64 @@
1
+ // Pure positioning math for anchored popovers (and, in a later
2
+ // phase, hover hints). Given the anchor and dialog rectangles plus
3
+ // a viewport, returns { top, left, resolvedPosition } in viewport
4
+ // (CSS `position: fixed`) coordinates.
5
+ //
6
+ // Supports:
7
+ // - position: "top" | "bottom" | "left" | "right"
8
+ // - align: "start" | "center" | "end" (cross-axis)
9
+ // - offset: pixel gap between anchor edge and dialog edge
10
+ // - autoFlip: if true, swap to the opposite side when the preferred
11
+ // placement would overflow the viewport AND the opposite
12
+ // side has room.
13
+ //
14
+ // The result is clamped on the cross axis to keep the dialog at
15
+ // least `edgePadding` pixels inside the viewport. The primary axis is
16
+ // not clamped — auto-flip handles that and clamping would defeat the
17
+ // anchor relationship.
18
+
19
+ const DEFAULT_OFFSET = 4
20
+ const DEFAULT_EDGE_PADDING = 8
21
+
22
+ export function computePopoverPosition({
23
+ anchor,
24
+ dialog,
25
+ viewport,
26
+ position = "bottom",
27
+ align = "start",
28
+ offset = DEFAULT_OFFSET,
29
+ autoFlip = true,
30
+ edgePadding = DEFAULT_EDGE_PADDING
31
+ }) {
32
+ const a = anchor
33
+ const d = dialog
34
+ const vw = viewport.width
35
+ const vh = viewport.height
36
+ const off = Number.isFinite(offset) ? offset : DEFAULT_OFFSET
37
+
38
+ let resolved = position
39
+
40
+ if (autoFlip) {
41
+ if (resolved === "bottom" && a.bottom + off + d.height > vh && a.top - off - d.height >= 0) resolved = "top"
42
+ else if (resolved === "top" && a.top - off - d.height < 0 && a.bottom + off + d.height <= vh) resolved = "bottom"
43
+ else if (resolved === "right" && a.right + off + d.width > vw && a.left - off - d.width >= 0) resolved = "left"
44
+ else if (resolved === "left" && a.left - off - d.width < 0 && a.right + off + d.width <= vw) resolved = "right"
45
+ }
46
+
47
+ let top, left
48
+ if (resolved === "bottom" || resolved === "top") {
49
+ top = resolved === "bottom" ? a.bottom + off : a.top - off - d.height
50
+ if (align === "center") left = a.left + (a.width / 2) - (d.width / 2)
51
+ else if (align === "end") left = a.right - d.width
52
+ else left = a.left
53
+ // Clamp on the parallel (cross) axis.
54
+ left = Math.max(edgePadding, Math.min(left, vw - d.width - edgePadding))
55
+ } else {
56
+ left = resolved === "right" ? a.right + off : a.left - off - d.width
57
+ if (align === "center") top = a.top + (a.height / 2) - (d.height / 2)
58
+ else if (align === "end") top = a.bottom - d.height
59
+ else top = a.top
60
+ top = Math.max(edgePadding, Math.min(top, vh - d.height - edgePadding))
61
+ }
62
+
63
+ return { top, left, resolvedPosition: resolved }
64
+ }