hibiki_rails 0.5.0 → 0.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/lib/generators/hibiki/rails/generator_helpers.rb +1 -2
- data/lib/generators/hibiki/rails/install/install_generator.rb +1 -2
- data/lib/generators/hibiki/rails/install/templates/hibiki_controller.js.tt +3 -6
- data/lib/generators/hibiki/rails/island/templates/channel.rb.tt +1 -3
- data/lib/generators/hibiki/rails/island/templates/display.html.erb.tt +1 -2
- data/lib/generators/hibiki/rails/island/templates/island.html.erb.tt +2 -6
- data/lib/generators/hibiki/rails/phlex/phlex_generator.rb +3 -4
- data/lib/generators/hibiki/rails/phlex/templates/channel.rb.tt +1 -4
- data/lib/generators/hibiki/rails/phlex/templates/component.rb.tt +3 -8
- data/lib/generators/hibiki/rails/phlex/templates/island_component.rb.tt +3 -5
- data/lib/generators/hibiki/rails/scaffold/USAGE +4 -5
- data/lib/generators/hibiki/rails/scaffold_controller/USAGE +10 -13
- data/lib/generators/hibiki/rails/scaffold_controller/templates/daisyui/views/_pagination.html.erb.tt +9 -37
- data/lib/generators/hibiki/rails/scaffold_controller/templates/none/views/_pagination.html.erb.tt +9 -24
- data/lib/generators/hibiki/rails/scaffold_controller/templates/phlex/daisyui/views/pagination.rb.tt +10 -45
- data/lib/generators/hibiki/rails/scaffold_controller/templates/phlex/none/views/pagination.rb.tt +11 -43
- data/lib/generators/hibiki/rails/scaffold_controller/templates/phlex/shared/views/controls.rb.tt +9 -42
- data/lib/generators/hibiki/rails/scaffold_controller/templates/phlex/shared/views/field_error.rb.tt +0 -5
- data/lib/generators/hibiki/rails/scaffold_controller/templates/phlex/shared/views/form.rb.tt +2 -10
- data/lib/generators/hibiki/rails/scaffold_controller/templates/phlex/shared/views/index.rb.tt +7 -21
- data/lib/generators/hibiki/rails/scaffold_controller/templates/phlex/shared/views/list.rb.tt +9 -34
- data/lib/generators/hibiki/rails/scaffold_controller/templates/phlex/shared/views/row.rb.tt +11 -35
- data/lib/generators/hibiki/rails/scaffold_controller/templates/phlex/shared/views/row_form.rb.tt +13 -34
- data/lib/generators/hibiki/rails/scaffold_controller/templates/phlex/shared/views/show.rb.tt +3 -8
- data/lib/generators/hibiki/rails/scaffold_controller/templates/phlex/tailwind/views/pagination.rb.tt +10 -49
- data/lib/generators/hibiki/rails/scaffold_controller/templates/shared/channel.rb.tt +32 -129
- data/lib/generators/hibiki/rails/scaffold_controller/templates/shared/controller.rb.tt +2 -4
- data/lib/generators/hibiki/rails/scaffold_controller/templates/shared/form.rb.tt +5 -16
- data/lib/generators/hibiki/rails/scaffold_controller/templates/shared/hibiki_busy.css.tt +20 -63
- data/lib/generators/hibiki/rails/scaffold_controller/templates/shared/member_channel.rb.tt +10 -20
- data/lib/generators/hibiki/rails/scaffold_controller/templates/shared/query.rb.tt +16 -76
- data/lib/generators/hibiki/rails/scaffold_controller/templates/shared/row.rb.tt +3 -11
- data/lib/generators/hibiki/rails/scaffold_controller/templates/shared/views/_controls.html.erb.tt +10 -41
- data/lib/generators/hibiki/rails/scaffold_controller/templates/shared/views/_form.html.erb.tt +1 -5
- data/lib/generators/hibiki/rails/scaffold_controller/templates/shared/views/_list.html.erb.tt +7 -33
- data/lib/generators/hibiki/rails/scaffold_controller/templates/shared/views/_row.html.erb.tt +10 -33
- data/lib/generators/hibiki/rails/scaffold_controller/templates/shared/views/_row_form.html.erb.tt +11 -34
- data/lib/generators/hibiki/rails/scaffold_controller/templates/shared/views/index.html.erb.tt +7 -21
- data/lib/generators/hibiki/rails/scaffold_controller/templates/shared/views/show.html.erb.tt +3 -9
- data/lib/generators/hibiki/rails/scaffold_controller/templates/tailwind/views/_pagination.html.erb.tt +9 -25
- data/lib/generators/hibiki/rails/scaffold_model_injection.rb +8 -21
- data/lib/generators/hibiki/rails/scaffold_parent_injection.rb +4 -21
- data/lib/generators/hibiki/rails/scaffold_parent_notices.rb +6 -9
- data/lib/generators/hibiki/rails/scaffold_phlex_helpers.rb +5 -7
- data/lib/generators/hibiki/rails/scaffold_post_install.rb +11 -14
- data/lib/generators/hibiki/rails/scaffold_transport_stylesheet.rb +3 -3
- data/lib/generators/hibiki/rails/stimulus/templates/channel.rb.tt +1 -3
- data/lib/generators/hibiki/rails/stimulus/templates/display.html.erb.tt +1 -2
- data/lib/generators/hibiki/rails/stimulus/templates/island.html.erb.tt +1 -3
- data/lib/hibiki/rails/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cd126c85e743e5ec9c89e54a1ffaba4cb04e6b6b0ef89868d60023168a0936a7
|
|
4
|
+
data.tar.gz: 00b4dfa1606348df1039cf5b69d1129c170fd418966b3db120964b71eba1e1c6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3c1e7d75c946f79cc898c20c2c3a8457ba78c152963f8b8155dd70a26308c138b31acc4b7a732e037d6bc28e933fb542a509d2dabee2e03602727d7e5e81b6d6
|
|
7
|
+
data.tar.gz: 6edf4361a4edbda81b933167cb6a7e08030cb50aac694c601a22c2210036eab5c56b101a449d3ea174a5485347e7c9c6e1cc86f9da123cbfe02e0e1ed34f41dd
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,26 @@ The gem and the npm package are released in lockstep and share these version
|
|
|
4
4
|
numbers — `app/assets/javascripts/hibiki.js` is a single copy served both ways,
|
|
5
5
|
so importmap and bundler apps always resolve identical client code.
|
|
6
6
|
|
|
7
|
+
## 0.5.1 — 2026-08-08
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
**Generator output and messages slimmed down.** The scaffold templates used to
|
|
12
|
+
carry long design-rationale comments into every generated file; they are now
|
|
13
|
+
one-to-three-line hints, with the docs holding the prose. The safety notes a
|
|
14
|
+
user editing the file actually needs stayed: public channel methods are
|
|
15
|
+
client-invocable actions, ActionCable's exact-arity rule, the untrusted
|
|
16
|
+
subscribe param, Phlex omitting `false`-valued attributes, and the busy
|
|
17
|
+
stylesheet's do-not-wrap-in-a-layer rule.
|
|
18
|
+
|
|
19
|
+
The generators' status notices were shortened the same way — they still say
|
|
20
|
+
what to do, just not why at essay length.
|
|
21
|
+
|
|
22
|
+
No behavior change anywhere: no code inside any template moved, and neither
|
|
23
|
+
the runtime nor the packaged client changed (the npm 0.5.1 exists only to keep
|
|
24
|
+
the lockstep rule). Re-running a scaffold with `--force` rewrites the views
|
|
25
|
+
with the shorter comments; that diff is the whole upgrade.
|
|
26
|
+
|
|
7
27
|
## 0.5.0 — 2026-08-05
|
|
8
28
|
|
|
9
29
|
### Added
|
|
@@ -71,8 +71,7 @@ module Hibiki
|
|
|
71
71
|
def wiring_hint
|
|
72
72
|
return if hibiki_registered? && helpers_included?
|
|
73
73
|
|
|
74
|
-
say_status :hint, "the packaged client is not fully wired " \
|
|
75
|
-
"(register line and/or Helpers include) — run: " \
|
|
74
|
+
say_status :hint, "the packaged client is not fully wired. Run: " \
|
|
76
75
|
"bin/rails g hibiki:rails:install", :yellow
|
|
77
76
|
end
|
|
78
77
|
end
|
|
@@ -103,8 +103,7 @@ module Hibiki
|
|
|
103
103
|
|
|
104
104
|
def bundler_note
|
|
105
105
|
say_status :skip, "#{IMPORTMAP} not found — with a JS bundler, " \
|
|
106
|
-
"npm/yarn add hibiki-rails instead
|
|
107
|
-
"@rails/actioncable)", :yellow
|
|
106
|
+
"npm/yarn/bun add hibiki-rails instead", :yellow
|
|
108
107
|
end
|
|
109
108
|
end
|
|
110
109
|
end
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
// Registers the packaged hibiki client
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// identifier in data-controller. File-backed on purpose: `bin/rails
|
|
5
|
-
// stimulus:manifest:update` re-derives this exact registration from the
|
|
6
|
-
// filename, so it survives manifest rewrites.
|
|
1
|
+
// Registers the packaged hibiki client as "hibiki" Stimulus controller.
|
|
2
|
+
// `bin/rails stimulus:manifest:update` re-derives this,
|
|
3
|
+
// so it survives manifest rewrites.
|
|
7
4
|
export { default } from "hibiki-rails"
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Generated by hibiki:rails:island — a working mini-example: one state,
|
|
4
|
-
# one derived, one action, one broadcasting effect.
|
|
5
|
-
# actor, the root, the per-action batch, and the [channel_name, cid]
|
|
6
|
-
# stream convention; this class is just the graph and its actions.
|
|
4
|
+
# one derived, one action, one broadcasting effect.
|
|
7
5
|
class <%= class_name %>Channel < ApplicationCable::Channel
|
|
8
6
|
include Hibiki::Rails::Channel
|
|
9
7
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
<%%# The root id is the
|
|
2
|
-
channel effect's target. %>
|
|
1
|
+
<%%# The root id is the replacement key. Keep in sync with channel effect's target. %>
|
|
3
2
|
<p id="<%= display_dom_id %>">
|
|
4
3
|
count: <strong><%%= count %></strong> · doubled: <strong><%%= doubled %></strong>
|
|
5
4
|
</p>
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
<%%#
|
|
2
|
-
write the underlying data attributes by hand, they are private to the
|
|
3
|
-
gem and version with its packaged JS. %>
|
|
1
|
+
<%%# Reactive island generated by hibiki_rails %>
|
|
4
2
|
<%% cid = local_assigns.fetch(:cid) { SecureRandom.uuid } %>
|
|
5
3
|
<%%= tag.div(**hibiki_island(<%= class_name %>Channel, cid:)) do %>
|
|
6
4
|
<%%= turbo_stream_from "<%= stream_name %>", cid %>
|
|
7
5
|
|
|
8
|
-
<%%#
|
|
9
|
-
Turbo stream above confirms, so the graph's first broadcast replaces
|
|
10
|
-
this. %>
|
|
6
|
+
<%%# Placeholder only: the graph's first broadcast replaces this. %>
|
|
11
7
|
<%%= render "<%= view_dir %>/<%= file_name %>_display", count: 0, doubled: 0 %>
|
|
12
8
|
|
|
13
9
|
<p><%%= tag.button("+1", **on(:increment)) %></p>
|
|
@@ -27,9 +27,8 @@ module Hibiki
|
|
|
27
27
|
def warn_without_hibiki_phlex
|
|
28
28
|
require "hibiki/phlex"
|
|
29
29
|
rescue LoadError
|
|
30
|
-
say_status :warn, "hibiki_phlex is not in this bundle
|
|
31
|
-
"
|
|
32
|
-
"(and `gem \"phlex-rails\"` to render components from views).", :yellow
|
|
30
|
+
say_status :warn, "hibiki_phlex is not in this bundle. " \
|
|
31
|
+
"Add `gem \"hibiki_phlex\"`.", :yellow
|
|
33
32
|
end
|
|
34
33
|
|
|
35
34
|
def create_channel
|
|
@@ -64,7 +63,7 @@ module Hibiki
|
|
|
64
63
|
def register_hint
|
|
65
64
|
return if hibiki_registered?
|
|
66
65
|
|
|
67
|
-
say_status :hint, "the packaged client is not registered
|
|
66
|
+
say_status :hint, "the packaged client is not registered. Run: " \
|
|
68
67
|
"bin/rails g hibiki:rails:install", :yellow
|
|
69
68
|
end
|
|
70
69
|
end
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# Generated by hibiki:rails:phlex
|
|
4
|
-
# (Hibiki::Reactive); the channel owns the transport. One render effect,
|
|
5
|
-
# re-rendering THE SAME INSTANCE, its HTML transmitted over the channel's
|
|
6
|
-
# own subscription and swapped in by the fragment's root DOM id.
|
|
3
|
+
# Generated by hibiki:rails:phlex
|
|
7
4
|
class <%= class_name %>Channel < ApplicationCable::Channel
|
|
8
5
|
include Hibiki::Rails::Channel
|
|
9
6
|
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# Generated by hibiki:rails:phlex
|
|
4
|
-
# is a plain Ruby object: Hibiki::Reactive gives it per-instance signals
|
|
5
|
-
# read as ordinary method calls (no .value anywhere), Rerenderable lets
|
|
6
|
-
# the channel's render effect re-render this same instance, and Helpers
|
|
7
|
-
# stamps the client's wire protocol.
|
|
3
|
+
# Generated by hibiki:rails:phlex
|
|
8
4
|
class Components::<%= class_name %> < Phlex::HTML
|
|
9
5
|
include Hibiki::Reactive
|
|
10
6
|
include Hibiki::Phlex::Rerenderable
|
|
@@ -14,11 +10,10 @@ class Components::<%= class_name %> < Phlex::HTML
|
|
|
14
10
|
derived(:doubled) { count * 2 }
|
|
15
11
|
|
|
16
12
|
def view_template
|
|
17
|
-
# The root id is the swap key for transmitted fragments
|
|
13
|
+
# The root id is the swap key for transmitted fragments; keep page-unique.
|
|
18
14
|
div(id: "<%= component_dom_id %>") do
|
|
19
15
|
p { "count: #{count} · doubled: #{doubled}" }
|
|
20
|
-
#
|
|
21
|
-
# delegation keeps the button working across replacements.
|
|
16
|
+
# The island's delegation keeps the button working across replacements.
|
|
22
17
|
button(**on(:increment)) { "+1" }
|
|
23
18
|
end
|
|
24
19
|
end
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
3
|
+
# Generated by hibiki:rails:phlex
|
|
4
|
+
# Render from any page:
|
|
6
5
|
# <%%= render Components::<%= class_name %>Island.new %>
|
|
7
6
|
class Components::<%= class_name %>Island < Phlex::HTML
|
|
8
7
|
include Hibiki::Rails::Helpers
|
|
9
8
|
|
|
10
9
|
def view_template
|
|
11
10
|
div(**hibiki_island(<%= class_name %>Channel, cid: SecureRandom.uuid)) do
|
|
12
|
-
#
|
|
13
|
-
# channel's long-lived instance takes over from its first transmit.
|
|
11
|
+
# Placeholder; the channel takes over from the first transmit.
|
|
14
12
|
render Components::<%= class_name %>.new
|
|
15
13
|
end
|
|
16
14
|
end
|
|
@@ -8,9 +8,9 @@ Description:
|
|
|
8
8
|
Everything is derived from the field list you pass, exactly as Rails'
|
|
9
9
|
scaffold derives its own output. Stock `rails g scaffold` is untouched.
|
|
10
10
|
|
|
11
|
-
The generated index is live: search, filter, sort and pagination are
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
The generated index is live: search, filter, sort, and pagination are all
|
|
12
|
+
reactive, edits happen in place, and changes from anywhere update every open
|
|
13
|
+
list.
|
|
14
14
|
|
|
15
15
|
Example:
|
|
16
16
|
bin/rails generate hibiki:rails:scaffold Book title:string author:references
|
|
@@ -29,8 +29,7 @@ Example:
|
|
|
29
29
|
And add to config/routes.rb:
|
|
30
30
|
resources :books
|
|
31
31
|
|
|
32
|
-
Restart the server afterwards
|
|
33
|
-
app/* glob at boot, and app/forms is new.
|
|
32
|
+
Restart the server afterwards if it is running — app/forms is new.
|
|
34
33
|
|
|
35
34
|
Pass --phlex to emit Phlex components under app/views/books/*.rb instead of
|
|
36
35
|
ERB templates. The view layer is the only thing it changes; it needs the
|
|
@@ -1,21 +1,18 @@
|
|
|
1
1
|
Description:
|
|
2
|
-
Generates a reactive CRUD resource for a model that
|
|
3
|
-
overlay half of hibiki:rails:scaffold.
|
|
2
|
+
Generates a reactive CRUD resource for a model that already exists.
|
|
4
3
|
|
|
5
|
-
With no field list the model's
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
migrated yet.
|
|
4
|
+
With no field list, the model's schema is used to determine columns, types,
|
|
5
|
+
associations, and validators. Pass fields explicitly to override this or
|
|
6
|
+
when the table hasn't been migrated yet.
|
|
9
7
|
|
|
10
|
-
The generated index is live: search, filter, sort and pagination are
|
|
11
|
-
|
|
8
|
+
The generated index is live: search, filter, sort, and pagination are all
|
|
9
|
+
reactive, edits happen in place, and changes from anywhere update every open
|
|
12
10
|
list.
|
|
13
11
|
|
|
14
|
-
Two models are MODIFIED. This one gets a delegate
|
|
15
|
-
after_commit broadcast
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
idempotent, both are announced, and anything already declared is left alone.
|
|
12
|
+
Two models are MODIFIED. This one gets a delegate for each belongs_to and
|
|
13
|
+
an after_commit broadcast. The related models get the missing has_many
|
|
14
|
+
association and a ping so changes are reflected here. Existing declarations
|
|
15
|
+
are left alone.
|
|
19
16
|
|
|
20
17
|
Example:
|
|
21
18
|
bin/rails generate hibiki:rails:scaffold_controller Book
|
data/lib/generators/hibiki/rails/scaffold_controller/templates/daisyui/views/_pagination.html.erb.tt
CHANGED
|
@@ -2,44 +2,19 @@
|
|
|
2
2
|
item as two tokens (`join-item btn`), so each of the six variants below can
|
|
3
3
|
repeat them inline — which is exactly what plain Tailwind cannot do. -%>
|
|
4
4
|
<%%# locals: (page: 1, page_count: 1) -%>
|
|
5
|
-
<%%# The numbered page control
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
at pages that no longer exist.
|
|
11
|
-
|
|
12
|
-
SCROLL. The links are anchors to the list, not buttons, and that IS the
|
|
13
|
-
scroll answer — the client only preventDefaults `submit`, so the click both
|
|
14
|
-
performs the action and does the browser's own fragment jump, which puts the
|
|
15
|
-
top of the list back in view exactly as a full page load would. No client
|
|
16
|
-
capability needed. data-turbo="false" keeps Turbo Drive out of it: a
|
|
17
|
-
same-page hash with Turbo off is a plain scroll, not a navigation.
|
|
18
|
-
|
|
19
|
-
No generation token — a page number is idempotent, so a double fire is one
|
|
20
|
-
write and one render.
|
|
21
|
-
|
|
22
|
-
`on` returns a { data: } hash, so an element needing its OWN data attributes
|
|
23
|
-
has to MERGE rather than splat: a bare ** after `data: { turbo: false }`
|
|
24
|
-
would silently replace it and the anchor would stop scrolling. %>
|
|
25
|
-
<%%# PENDING. Nothing here asks for it: the client stamps data-hibiki-busy on
|
|
26
|
-
the control that fired, so the clicked page link dims itself while the trip
|
|
27
|
-
is out, and the swap that answers it destroys the attribute along with the
|
|
28
|
-
link. The bar above the list is the other half — the anchor jump has
|
|
29
|
-
already put it in view by then. %>
|
|
5
|
+
<%%# The numbered page control, inside the replaced fragment so it re-renders
|
|
6
|
+
with the list. The links are anchors to the list, so a click also does the
|
|
7
|
+
browser's own fragment jump; data-turbo="false" keeps Turbo Drive out.
|
|
8
|
+
`on` returns a { data: } hash — merge, don't splat, or the anchor stops
|
|
9
|
+
scrolling. %>
|
|
30
10
|
<%% page_data = ->(n) { { turbo: false }.merge(on(:go_to_page, with: { page: n })[:data]) } %>
|
|
31
|
-
<%%# The
|
|
32
|
-
|
|
33
|
-
its own — with no page control it is empty, and padding here would leave
|
|
34
|
-
dead vertical space on a list that has none. %>
|
|
11
|
+
<%%# The wrapper always renders (so idiomorph has a node to pair with) and
|
|
12
|
+
stays bare — layout classes here would leave dead space when empty. %>
|
|
35
13
|
<div id="<%= pagination_dom_id %>">
|
|
36
14
|
<%% if page_count > 1 %>
|
|
37
15
|
<nav<%= css_attr(:pagination_nav) %> aria-label="Pagination">
|
|
38
|
-
<%%# Prev/next
|
|
39
|
-
|
|
40
|
-
one that reflows under the pointer is how you mis-click a list that
|
|
41
|
-
just repainted. A span, not a disabled link: there is no page to
|
|
42
|
-
name, so there is no action to stamp. %>
|
|
16
|
+
<%%# Prev/next go inert at the ends rather than disappearing, so the
|
|
17
|
+
control keeps its width across a page change. %>
|
|
43
18
|
<%% if page == 1 %>
|
|
44
19
|
<span class="join-item btn btn-disabled" aria-disabled="true">«</span>
|
|
45
20
|
<%% else %>
|
|
@@ -51,9 +26,6 @@
|
|
|
51
26
|
<%% if n.nil? %>
|
|
52
27
|
<span class="join-item btn btn-disabled" aria-hidden="true">…</span>
|
|
53
28
|
<%% elsif n == page %>
|
|
54
|
-
<%%# aria-current is the only thing that tells a screen reader which
|
|
55
|
-
page it is on: the visual cue is a class, and the link text is
|
|
56
|
-
just a number either way. %>
|
|
57
29
|
<span class="join-item btn btn-active" aria-current="page"><%%= n %></span>
|
|
58
30
|
<%% else %>
|
|
59
31
|
<%%= link_to n, "#<%= list_dom_id %>", class: "join-item btn",
|
data/lib/generators/hibiki/rails/scaffold_controller/templates/none/views/_pagination.html.erb.tt
CHANGED
|
@@ -2,36 +2,21 @@
|
|
|
2
2
|
the current page with a CLASS (btn-active, or a background utility). With
|
|
3
3
|
no stylesheet there is nothing to carry that signal, so the current page
|
|
4
4
|
has to change ELEMENT — <strong> rather than a styled <span> — and the
|
|
5
|
-
inert prev/next markers become plain text.
|
|
6
|
-
for a screen reader either way; what changes is that sighted users need the
|
|
7
|
-
element, because there is no stylesheet to help. A class-token map cannot
|
|
5
|
+
inert prev/next markers become plain text. A class-token map cannot
|
|
8
6
|
express a change of tag name. -%>
|
|
9
7
|
<%%# locals: (page: 1, page_count: 1) -%>
|
|
10
|
-
<%%# The numbered page control
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
preventDefaults `submit`, so the click both performs the action and does the
|
|
16
|
-
browser's own fragment jump. data-turbo="false" keeps Turbo Drive out of it.
|
|
17
|
-
|
|
18
|
-
`on` returns a { data: } hash, so an element needing its OWN data attributes
|
|
19
|
-
has to MERGE rather than splat, or the anchor stops scrolling. %>
|
|
20
|
-
<%%# PENDING. Nothing here asks for it: the client stamps data-hibiki-busy on
|
|
21
|
-
the control that fired, so the clicked page link dims itself while the trip
|
|
22
|
-
is out, and the swap that answers it destroys the attribute along with the
|
|
23
|
-
link. The bar above the list is the other half — the anchor jump has
|
|
24
|
-
already put it in view by then. %>
|
|
8
|
+
<%%# The numbered page control, inside the replaced fragment so it re-renders
|
|
9
|
+
with the list. The links are anchors to the list, so a click also does the
|
|
10
|
+
browser's own fragment jump; data-turbo="false" keeps Turbo Drive out.
|
|
11
|
+
`on` returns a { data: } hash — merge, don't splat, or the anchor stops
|
|
12
|
+
scrolling. %>
|
|
25
13
|
<%% page_data = ->(n) { { turbo: false }.merge(on(:go_to_page, with: { page: n })[:data]) } %>
|
|
26
|
-
<%%# The
|
|
27
|
-
pair with. %>
|
|
14
|
+
<%%# The wrapper always renders, so idiomorph always has a node to pair with. %>
|
|
28
15
|
<div id="<%= pagination_dom_id %>">
|
|
29
16
|
<%% if page_count > 1 %>
|
|
30
17
|
<nav aria-label="Pagination">
|
|
31
|
-
<%%# Prev/next
|
|
32
|
-
|
|
33
|
-
A span, not a disabled link: there is no page to name, so there is no
|
|
34
|
-
action to stamp. %>
|
|
18
|
+
<%%# Prev/next go inert at the ends rather than disappearing, so the
|
|
19
|
+
control keeps its position across a page change. %>
|
|
35
20
|
<%% if page == 1 %>
|
|
36
21
|
<span aria-disabled="true">«</span>
|
|
37
22
|
<%% else %>
|
data/lib/generators/hibiki/rails/scaffold_controller/templates/phlex/daisyui/views/pagination.rb.tt
CHANGED
|
@@ -1,43 +1,17 @@
|
|
|
1
1
|
<%#- ESCAPING: none — plain Ruby out, every <% is generation time. -%>
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
# The numbered page control
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# never be re-rendered and could only ever change its TEXT (reactive values are
|
|
8
|
-
# textContent-only), leaving a control whose links point at pages that no
|
|
9
|
-
# longer exist.
|
|
10
|
-
#
|
|
11
|
-
# SCROLL. The links are anchors to the list, not buttons, and that IS the
|
|
12
|
-
# scroll answer — the client only preventDefaults `submit`, so the click both
|
|
13
|
-
# performs the action and does the browser's own fragment jump, which puts the
|
|
14
|
-
# top of the list back in view exactly as a full page load would. No client
|
|
15
|
-
# capability needed. data-turbo="false" keeps Turbo Drive out of it: a
|
|
16
|
-
# same-page hash with Turbo off is a plain scroll, not a navigation.
|
|
17
|
-
#
|
|
18
|
-
# THE STRING "false", not the boolean. Phlex OMITS a false-valued attribute
|
|
19
|
-
# entirely, so `turbo: false` would emit no data-turbo at all and Turbo Drive
|
|
20
|
-
# would take the click back. The ERB twin's boolean is right there and wrong
|
|
21
|
-
# here.
|
|
22
|
-
#
|
|
23
|
-
# No generation token — a page number is idempotent, so a double fire is one
|
|
24
|
-
# write and one render.
|
|
25
|
-
#
|
|
26
|
-
# PENDING. Nothing here asks for it: the client stamps data-hibiki-busy on the
|
|
27
|
-
# control that fired, so the clicked page link dims itself while the trip is
|
|
28
|
-
# out, and the swap that answers it destroys the attribute along with the link.
|
|
29
|
-
# The bar above the list is the other half — the anchor jump has already put it
|
|
30
|
-
# in view by then.
|
|
4
|
+
# The numbered page control, inside the replaced fragment so it re-renders
|
|
5
|
+
# with the list. The links are anchors to the list, so a click also does the
|
|
6
|
+
# browser's own fragment jump; data-turbo="false" keeps Turbo Drive out.
|
|
31
7
|
class <%= view_class_name(:pagination) %> < Views::Base
|
|
32
8
|
<%= phlex_includes(:link_to, hibiki: true) %>
|
|
33
9
|
|
|
34
10
|
<%= initializer_source([%w[page 1], %w[page_count 1]]) %>
|
|
35
11
|
|
|
36
12
|
def view_template
|
|
37
|
-
# The
|
|
38
|
-
#
|
|
39
|
-
# of its own — with no page control it is empty, and padding here would
|
|
40
|
-
# leave dead vertical space on a list that has none.
|
|
13
|
+
# The wrapper always renders (so idiomorph has a node to pair with) and
|
|
14
|
+
# stays bare — layout classes here would leave dead space when empty.
|
|
41
15
|
div(id: "<%= pagination_dom_id %>") do
|
|
42
16
|
nav<%= arg_list(*css_args(:pagination_nav), %(aria_label: "Pagination")) %> { items } if @page_count > 1
|
|
43
17
|
end
|
|
@@ -46,11 +20,8 @@ class <%= view_class_name(:pagination) %> < Views::Base
|
|
|
46
20
|
private
|
|
47
21
|
|
|
48
22
|
def items
|
|
49
|
-
# Prev/next
|
|
50
|
-
#
|
|
51
|
-
# that reflows under the pointer is how you mis-click a list that just
|
|
52
|
-
# repainted. A span, not a disabled link: there is no page to name, so
|
|
53
|
-
# there is no action to stamp.
|
|
23
|
+
# Prev/next go inert at the ends rather than disappearing, so the control
|
|
24
|
+
# keeps its width across a page change.
|
|
54
25
|
@page == 1 ? inert("«") : step("«", @page - 1, rel: "prev", label: "Previous page")
|
|
55
26
|
whitespace
|
|
56
27
|
|
|
@@ -58,16 +29,12 @@ class <%= view_class_name(:pagination) %> < Views::Base
|
|
|
58
29
|
if n.nil?
|
|
59
30
|
span(class: "join-item btn btn-disabled", aria_hidden: "true") { "…" }
|
|
60
31
|
elsif n == @page
|
|
61
|
-
# aria-current is the only thing that tells a screen reader which page
|
|
62
|
-
# it is on: the visual cue is a class, and the link text is just a
|
|
63
|
-
# number either way.
|
|
64
32
|
span(class: "join-item btn btn-active", aria_current: "page") { n.to_s }
|
|
65
33
|
else
|
|
66
34
|
step(n.to_s, n, label: "Page #{n}")
|
|
67
35
|
end
|
|
68
36
|
|
|
69
|
-
# Phlex emits nothing between siblings
|
|
70
|
-
# together, which under --css=none is all there is to separate them.
|
|
37
|
+
# Phlex emits nothing between siblings.
|
|
71
38
|
whitespace
|
|
72
39
|
end
|
|
73
40
|
|
|
@@ -78,10 +45,8 @@ class <%= view_class_name(:pagination) %> < Views::Base
|
|
|
78
45
|
span(class: "join-item btn btn-disabled", aria_disabled: "true") { glyph }
|
|
79
46
|
end
|
|
80
47
|
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
# `data: { turbo: "false" }` would silently replace it and the anchor would
|
|
84
|
-
# stop scrolling.
|
|
48
|
+
# The STRING "false", not the boolean — Phlex omits false-valued attributes.
|
|
49
|
+
# And merge, don't splat: the anchor needs its own data attribute too.
|
|
85
50
|
def step(text, n, label:, rel: nil)
|
|
86
51
|
link_to text, "#<%= list_dom_id %>", class: "join-item btn", rel:, "aria-label": label,
|
|
87
52
|
data: { turbo: "false" }.merge(on(:go_to_page, with: { page: n })[:data])
|
data/lib/generators/hibiki/rails/scaffold_controller/templates/phlex/none/views/pagination.rb.tt
CHANGED
|
@@ -1,48 +1,19 @@
|
|
|
1
1
|
<%#- ESCAPING: none — plain Ruby out, every <% is generation time. -%>
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
# The numbered page control
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# never be re-rendered and could only ever change its TEXT (reactive values are
|
|
8
|
-
# textContent-only), leaving a control whose links point at pages that no
|
|
9
|
-
# longer exist.
|
|
4
|
+
# The numbered page control, inside the replaced fragment so it re-renders
|
|
5
|
+
# with the list. The links are anchors to the list, so a click also does the
|
|
6
|
+
# browser's own fragment jump; data-turbo="false" keeps Turbo Drive out.
|
|
10
7
|
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# performs the action and does the browser's own fragment jump, which puts the
|
|
14
|
-
# top of the list back in view exactly as a full page load would. No client
|
|
15
|
-
# capability needed. data-turbo="false" keeps Turbo Drive out of it: a
|
|
16
|
-
# same-page hash with Turbo off is a plain scroll, not a navigation.
|
|
17
|
-
#
|
|
18
|
-
# THE STRING "false", not the boolean. Phlex OMITS a false-valued attribute
|
|
19
|
-
# entirely, so `turbo: false` would emit no data-turbo at all and Turbo Drive
|
|
20
|
-
# would take the click back. The ERB twin's boolean is right there and wrong
|
|
21
|
-
# here.
|
|
22
|
-
#
|
|
23
|
-
# No generation token — a page number is idempotent, so a double fire is one
|
|
24
|
-
# write and one render.
|
|
25
|
-
#
|
|
26
|
-
# PENDING. Nothing here asks for it: the client stamps data-hibiki-busy on the
|
|
27
|
-
# control that fired, so the clicked page link dims itself while the trip is
|
|
28
|
-
# out, and the swap that answers it destroys the attribute along with the link.
|
|
29
|
-
# The bar above the list is the other half — the anchor jump has already put it
|
|
30
|
-
# in view by then.
|
|
31
|
-
#
|
|
32
|
-
# The sharpest of the three forks, and the one Phlex does NOT dissolve. Both
|
|
33
|
-
# styled variants mark the current page with a CLASS. With no stylesheet there
|
|
34
|
-
# is nothing to carry that signal, so the current page has to change ELEMENT —
|
|
35
|
-
# strong rather than a styled span — and the inert prev/next markers become
|
|
36
|
-
# plain text. aria-current still does the work for a screen reader either way;
|
|
37
|
-
# what changes is that sighted users need the element.
|
|
8
|
+
# Unstyled, so the current page changes ELEMENT (strong) — there is no class
|
|
9
|
+
# to carry the signal.
|
|
38
10
|
class <%= view_class_name(:pagination) %> < Views::Base
|
|
39
11
|
<%= phlex_includes(:link_to, hibiki: true) %>
|
|
40
12
|
|
|
41
13
|
<%= initializer_source([%w[page 1], %w[page_count 1]]) %>
|
|
42
14
|
|
|
43
15
|
def view_template
|
|
44
|
-
# The
|
|
45
|
-
# pair with.
|
|
16
|
+
# The wrapper always renders, so idiomorph always has a node to pair with.
|
|
46
17
|
div(id: "<%= pagination_dom_id %>") do
|
|
47
18
|
nav(aria_label: "Pagination") { items } if @page_count > 1
|
|
48
19
|
end
|
|
@@ -51,10 +22,8 @@ class <%= view_class_name(:pagination) %> < Views::Base
|
|
|
51
22
|
private
|
|
52
23
|
|
|
53
24
|
def items
|
|
54
|
-
# Prev/next
|
|
55
|
-
#
|
|
56
|
-
# span, not a disabled link: there is no page to name, so there is no
|
|
57
|
-
# action to stamp.
|
|
25
|
+
# Prev/next go inert at the ends rather than disappearing, so the control
|
|
26
|
+
# keeps its position across a page change.
|
|
58
27
|
@page == 1 ? inert("«") : step("«", @page - 1, rel: "prev", label: "Previous page")
|
|
59
28
|
whitespace
|
|
60
29
|
|
|
@@ -67,8 +36,7 @@ class <%= view_class_name(:pagination) %> < Views::Base
|
|
|
67
36
|
step(n.to_s, n, label: "Page #{n}")
|
|
68
37
|
end
|
|
69
38
|
|
|
70
|
-
# Phlex emits nothing between siblings
|
|
71
|
-
# together, which under --css=none is all there is to separate them.
|
|
39
|
+
# Phlex emits nothing between siblings.
|
|
72
40
|
whitespace
|
|
73
41
|
end
|
|
74
42
|
|
|
@@ -79,8 +47,8 @@ class <%= view_class_name(:pagination) %> < Views::Base
|
|
|
79
47
|
span(aria_disabled: "true") { glyph }
|
|
80
48
|
end
|
|
81
49
|
|
|
82
|
-
#
|
|
83
|
-
#
|
|
50
|
+
# The STRING "false", not the boolean — Phlex omits false-valued attributes.
|
|
51
|
+
# And merge, don't splat: the anchor needs its own data attribute too.
|
|
84
52
|
def step(text, n, label:, rel: nil)
|
|
85
53
|
link_to text, "#<%= list_dom_id %>", rel:, "aria-label": label,
|
|
86
54
|
data: { turbo: "false" }.merge(on(:go_to_page, with: { page: n })[:data])
|