katalyst-kpop 3.4.0 → 4.0.0.beta.1

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +92 -74
  3. data/app/assets/builds/katalyst/kpop.esm.js +463 -457
  4. data/app/assets/builds/katalyst/kpop.js +463 -457
  5. data/app/assets/builds/katalyst/kpop.min.js +1 -1
  6. data/app/assets/builds/katalyst/kpop.min.js.map +1 -1
  7. data/app/assets/stylesheets/katalyst/kpop.css +69 -0
  8. data/app/components/kpop/frame_component.html.erb +3 -14
  9. data/app/components/kpop/frame_component.rb +15 -11
  10. data/app/components/kpop/modal_component.html.erb +7 -6
  11. data/app/components/kpop/modal_component.rb +9 -32
  12. data/app/controllers/concerns/katalyst/kpop/frame_request.rb +67 -8
  13. data/app/javascript/kpop/application.js +68 -7
  14. data/app/javascript/kpop/controllers/frame_controller.js +96 -66
  15. data/app/javascript/kpop/modals/content_modal.js +2 -58
  16. data/app/javascript/kpop/modals/frame_modal.js +19 -76
  17. data/app/javascript/kpop/modals/modal.js +96 -49
  18. data/app/javascript/kpop/modals/stream_modal.js +11 -62
  19. data/app/javascript/kpop/utils/debug.js +22 -0
  20. data/app/javascript/kpop/utils/link_observer.js +151 -0
  21. data/app/javascript/kpop/utils/ruleset.js +43 -0
  22. data/app/javascript/kpop/utils/stream_actions.js +21 -0
  23. data/app/views/layouts/kpop/frame.html.erb +3 -1
  24. data/app/views/layouts/kpop/stream.html.erb +3 -0
  25. data/lib/katalyst/kpop/engine.rb +1 -8
  26. data/lib/katalyst/kpop/matchers/modal_matcher.rb +1 -1
  27. data/lib/katalyst/kpop/matchers/src_matcher.rb +33 -0
  28. data/lib/katalyst/kpop/matchers.rb +11 -40
  29. metadata +8 -19
  30. data/app/assets/stylesheets/katalyst/kpop/_frame.scss +0 -90
  31. data/app/assets/stylesheets/katalyst/kpop/_modal.scss +0 -88
  32. data/app/assets/stylesheets/katalyst/kpop/_scrim.scss +0 -46
  33. data/app/assets/stylesheets/katalyst/kpop/_side_panel.scss +0 -64
  34. data/app/assets/stylesheets/katalyst/kpop/_variables.scss +0 -24
  35. data/app/assets/stylesheets/katalyst/kpop.scss +0 -6
  36. data/app/components/kpop/modal/footer_component.rb +0 -21
  37. data/app/components/kpop/modal/header_component.rb +0 -21
  38. data/app/components/kpop/modal/title_component.html.erb +0 -6
  39. data/app/components/kpop/modal/title_component.rb +0 -28
  40. data/app/components/scrim_component.rb +0 -32
  41. data/app/helpers/kpop_helper.rb +0 -32
  42. data/app/javascript/kpop/controllers/modal_controller.js +0 -30
  43. data/app/javascript/kpop/controllers/scrim_controller.js +0 -159
  44. data/app/javascript/kpop/debug.js +0 -3
  45. data/app/javascript/kpop/turbo_actions.js +0 -46
  46. data/app/javascript/kpop/utils/stream_renderer.js +0 -15
  47. data/lib/katalyst/kpop/turbo.rb +0 -49
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 27a4ea5c3ebe0dbd090653e86fbdbbb6d78320e438a0b81219480699e773ff89
4
- data.tar.gz: 639fc2ae0935f2790515c341cc8fba874a5f28f6b6407f2ab6fb3cfac3a2a9b1
3
+ metadata.gz: '05194c96ae5a8f5f76c17281b67a59bfaf60d0cd2158570c3f382f791ca79c7d'
4
+ data.tar.gz: caf584f573bd0b72c4e5dc82e62024855d42ddda44a8cd5df20e22e5781bdaf9
5
5
  SHA512:
6
- metadata.gz: 5ef9acdf5044e9061b0bbdba49b7e41cac8aa1c941155c65ce5ac5b4506db888c1f5df8f2ee8e80e16c1ea889a99a1775f614d8f8c870e156877ad5d1d284dd7
7
- data.tar.gz: a13c0717510317bc97040df5278716e8c2e6efe186598f141bab0d75d11cba5cea92f339c869103ac68daf067a34e973a7d0bc65631d8ff2c5bcb36184e29a49
6
+ metadata.gz: 1a4730a3f750345522be09ca00590052ec8df79d200a826c5ed93d3f8a4cfb1fc1bbf70ab158faba6f16ba169ddcae4028ef177e351180cfda2c1e4f6ee08ce9
7
+ data.tar.gz: 6744d336c527e4452ffaf0456080adf8b90feabb532dc689695822e86e8c7e2ffb8df715bce6e2b59784264adb31b95b414187e576ffde775d8780c45eb28349
data/README.md CHANGED
@@ -1,127 +1,145 @@
1
1
  # kpop
2
2
 
3
- Modals driven by `@hotwire/turbo` frame navigation.
4
-
5
- kpop requires `@hotwire/turbo` and `@hotwire/stimulus` to be installed and configured correctly to be used.
3
+ Kpop delivers Turbo-powered modals for Rails applications. Version 4 rebuilds the integration so Turbo frames, Turbo Streams, Stimulus, and Turbo Native all share the same life cycle: focus is restored, history stays clean, and dialogs can reopen automatically after redirects. See `doc/upgrading-to-v4.md` if you are migrating from an earlier release.
6
4
 
7
5
  ## Installation
8
6
 
9
- Install gem
7
+ ### 1. Gem
8
+
10
9
  ```bash
11
10
  # Gemfile
12
-
13
- $ bundle add "katalyst-kpop"
11
+ bundle add "katalyst-kpop"
14
12
  ```
15
13
 
16
- kpop supports installation of javascript dependencies with either import maps or yarn.
14
+ ### 2. JavaScript package (Importmap)
17
15
 
18
- ### Stimulus controllers
16
+ ```ruby
17
+ # config/importmap.rb
18
+ pin "@katalyst/kpop", to: "katalyst/kpop.js", preload: true
19
+ ```
19
20
 
20
- kpop assumes that you are using importmaps to manage javascript dependencies.
21
+ ## Stimulus setup
21
22
 
22
- Add the following to your Stimulus `controllers/index.js`:
23
+ Register the provided controllers so `<turbo-frame id="kpop">` elements receive the `kpop--frame` behaviour.
23
24
 
24
25
  ```js
25
- import kpop from "@katalyst/kpop";
26
+ // app/javascript/controllers/index.js
27
+ import { application } from "./application";
28
+ import { controllers as kpop } from "@katalyst/kpop";
29
+
26
30
  application.load(kpop);
27
31
  ```
28
32
 
29
- This will ensure that kpop is loaded and registered with Stimulus.
30
-
31
- ### Stylesheets
33
+ ## Bootstrap the runtime
32
34
 
33
- Import stylesheets through using SASS using asset pipeline:
35
+ The package exports a client runtime that observes links, stamps the `Kpop-Available` header on Turbo fetches, and exposes a `kpop_open` Turbo Stream action. Configure it once during boot:
34
36
 
35
- ```scss
36
- // app/assets/stylesheets/application.scss
37
+ ```js
38
+ // app/javascript/application.js
39
+ import "@hotwired/turbo-rails";
40
+ import kpop from "@katalyst/kpop";
37
41
 
38
- @use "katalyst/kpop";
42
+ kpop
43
+ .configure({
44
+ rules: [
45
+ {
46
+ patterns: ["^/modal"],
47
+ properties: { context: "modal" },
48
+ },
49
+ ],
50
+ debug: false,
51
+ })
52
+ .start();
39
53
  ```
40
54
 
41
- ## Usage
55
+ Rules are regex strings matched against `location.pathname`. When `properties.context === "modal"`, the runtime sets `data-turbo-frame="kpop"` on hovered/focused links so Turbo prefetches them into the modal frame.
56
+
57
+ ## Render the frame
58
+
59
+ Every layout that can host a modal needs the frame near the end of `<body>`:
42
60
 
43
- kpop provides helpers to add a basic scrim and modal target frame. These should be placed inside the body:
44
- ```html
45
- <body>
46
- <%= render ScrimComponent.new %>
47
- <%= render Kpop::FrameComponent.new do %>
48
- <%= yield :kpop %>
49
- <% end %>
50
- </body>
61
+ ```erb
62
+ <!-- app/views/layouts/application.html.erb -->
63
+ <body>
64
+ <%= yield %>
65
+ <%= render Kpop::FrameComponent.new do %>
66
+ <%= yield :kpop %>
67
+ <% end %>
68
+ </body>
51
69
  ```
52
70
 
53
- ### Show a modal
71
+ `Kpop::FrameComponent` wires all Turbo life-cycle events into the Stimulus controller and automatically replays `flash[:modal_location]`. Use `content_for :kpop` only when you want to inject a modal during an ordinary page load.
54
72
 
55
- To show a modal you need to add content to the kpop turbo frame. You can do this in several ways:
56
- 1. Injection
57
- 2. Navigation
73
+ ## Controller integration
58
74
 
59
- ### Injection
60
- Use `content_for :kpop` in an HTML response to inject content into the kpop frame (see `yield :kpop` above).
75
+ Include the concern by calling `expects_kpop` in controllers that serve modals:
61
76
 
62
- This allows you to pre open modals when rendering a page without the need for user interaction.
77
+ ```ruby
78
+ class InvitationsController < ApplicationController
79
+ expects_kpop(only: %i[new create]) { root_path }
63
80
 
64
- ```html
65
- <!-- app/views/homepage/index.html.erb -->
66
- <h1>Site name</h1>
67
- ... more html content that will be rendered behind the scrim ...
81
+ def new
82
+ render layout: "kpop/frame"
83
+ end
68
84
 
69
- <% content_for :kpop do %>
70
- <%= render Kpop::ModalComponent.new(title: "Welcome") do %>
71
- Thanks for visiting our site!
72
- <% end %>
85
+ def create
86
+ if invitation.save
87
+ redirect_to(invitation_path(invitation), status: :see_other)
88
+ else
89
+ render :new, status: :unprocessable_content
90
+ end
91
+ end
92
+ end
73
93
  ```
74
94
 
75
- ### Navigation
76
- Respond to a turbo frame request from the kpop frame component.
95
+ When the JS runtime sets `Kpop-Available: true`, `expects_kpop` will:
77
96
 
78
- You can generate a link that will cause a modal to show using the `kpop_link_to` helper.
97
+ - Redirect full-page GET requests back with `flash[:modal_location]` so the modal reopens automatically.
98
+ - Wrap Turbo Stream renders in `turbo_stream.action(:kpop_open, "kpop", ...)`, letting the client swap dialogs without navigating.
99
+ - Override Turbo Native redirects so closing a modal can resume the historical location.
79
100
 
80
- `kpop_link_to`'s are similar to a `link_to` in rails, but it will navigate to the given URL within the modal turbo
81
- frame. The targeted action will need to generate content in a `Kpop::FrameComponent`, e.g. by responding to a turbo
82
- frame request with the ID `kpop`.
101
+ ## Triggering modals
83
102
 
84
- ```html
85
- <!-- app/views/homepage/index.html.erb -->
86
- <%= kpop_link_to "click to open modal", modal_path("example") %>
103
+ Use the helpers so links and forms always target the frame:
104
+
105
+ ```erb
106
+ <%= kpop_link_to "Invite a user", new_invitation_path %>
107
+ <%= kpop_button_to "Launch dialog", new_invitation_path %>
108
+ <%= kpop_button_close "Close" %>
87
109
  ```
88
110
 
89
- ```html
90
- <!-- app/views/modals/show.html.erb -->
91
- <%= render Kpop::ModalComponent.new(title: "Modal title") do %>
92
- Modal content
111
+ Inside the modal view render the provided component, which outputs a native `<dialog>` with the data attributes the Stimulus controller relies on:
112
+
113
+ ```erb
114
+ <%= render Kpop::ModalComponent.new(title: "Invite a user", modal_class: :invite) do %>
115
+ <%= render "form", invitation: @invitation %>
93
116
  <% end %>
94
117
  ```
95
118
 
96
- ### Turbo Frame Layout
119
+ ## Styling
97
120
 
98
- Turbo Frame navigation responses use a layout to add a basic document structure. The `turbo-rails` gem provides the
99
- `turbo_rails/frame` layout, and kpop provides a similar `kpop/frame` layout. If a turbo frame response is requested with
100
- the `kpop` ID, the `kpop/frame` layout will be used automatically. You can provide an alternative by setting `layout`
101
- in your controller, as usual.
121
+ Import the stylesheet (or `@use` the Sass entry) to get the default animations, scrim, and CSS custom properties:
102
122
 
103
- Turbo 8 assumes that the frame response will be a complete HTML document, including a `<head>` and `<body>`, and the
104
- Turbo Visits use the response head to deduce whether the navigation can be snap-shotted or not. This logic lives in
105
- `@hotwire/turbo` in the `Turbo.Visit` constructor:
123
+ ```scss
124
+ // app/assets/stylesheets/application.scss
125
+ @use "katalyst/kpop";
106
126
 
107
- ```javascript
108
- this.isSamePage = this.delegate.locationWithActionIsSamePage(this.location, this.action);
127
+ .kpop {
128
+ --animation-duration: 0.3s;
129
+ }
109
130
  ```
110
131
 
111
- If the page is not the same, then the visit is not snap-shotted. Detection looks at turbo-tracked elements in the page
112
- head to make this decision, and history navigation with frames will not work unless the headers are compatible.
132
+ Override the custom properties inside `.kpop` to change transitions or backdrop colours without rewriting JavaScript.
113
133
 
114
- As a consequence of this logic, it's really important that the layout used for kpop frame responses is compatible with
115
- the application layout. Kpop provides a "sensible default" that includes stylesheets and javascripts, but if your
116
- application doesn't use the same structure as the Rails default, you'll need to provide your own layout.
134
+ ## Further reading
117
135
 
118
- If you're experiencing 'strange history behaviour', it's worth putting a breakpoint on the turbo `isSamePage`
119
- calculation to check that the headers are compatible.
136
+ - `doc/upgrading-to-v4.md` &mdash; highlights everything that changed in the rewrite plus a migration checklist.
137
+ - `app/controllers/concerns/katalyst/kpop/frame_request.rb` &mdash; documents the `expects_kpop` behaviour in code.
138
+ - `spec/system/*` &mdash; demonstrate the UX guarantees (escape closes, history stays clean, redirects, etc.).
120
139
 
121
140
  ## Development
122
141
 
123
- Releases need to be distributed to rubygems.org and npmjs.org. To do this, you need to have accounts with both providers
124
- and be added as a collaborator to the kpop gem and npm packages.
142
+ Releases need to be distributed to rubygems.org and npmjs.org. To do this, you need to have accounts with both providers and be added as a collaborator to the kpop gem and npm packages.
125
143
 
126
144
  1. Update the version in `katalyst-kpop.gemspec` and run `bundle` to update `Gemfile.lock`
127
145
  2. Ensure that `rake` passes (format and tests)