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.
- checksums.yaml +4 -4
- data/README.md +92 -74
- data/app/assets/builds/katalyst/kpop.esm.js +463 -457
- data/app/assets/builds/katalyst/kpop.js +463 -457
- data/app/assets/builds/katalyst/kpop.min.js +1 -1
- data/app/assets/builds/katalyst/kpop.min.js.map +1 -1
- data/app/assets/stylesheets/katalyst/kpop.css +69 -0
- data/app/components/kpop/frame_component.html.erb +3 -14
- data/app/components/kpop/frame_component.rb +15 -11
- data/app/components/kpop/modal_component.html.erb +7 -6
- data/app/components/kpop/modal_component.rb +9 -32
- data/app/controllers/concerns/katalyst/kpop/frame_request.rb +67 -8
- data/app/javascript/kpop/application.js +68 -7
- data/app/javascript/kpop/controllers/frame_controller.js +96 -66
- data/app/javascript/kpop/modals/content_modal.js +2 -58
- data/app/javascript/kpop/modals/frame_modal.js +19 -76
- data/app/javascript/kpop/modals/modal.js +96 -49
- data/app/javascript/kpop/modals/stream_modal.js +11 -62
- data/app/javascript/kpop/utils/debug.js +22 -0
- data/app/javascript/kpop/utils/link_observer.js +151 -0
- data/app/javascript/kpop/utils/ruleset.js +43 -0
- data/app/javascript/kpop/utils/stream_actions.js +21 -0
- data/app/views/layouts/kpop/frame.html.erb +3 -1
- data/app/views/layouts/kpop/stream.html.erb +3 -0
- data/lib/katalyst/kpop/engine.rb +1 -8
- data/lib/katalyst/kpop/matchers/modal_matcher.rb +1 -1
- data/lib/katalyst/kpop/matchers/src_matcher.rb +33 -0
- data/lib/katalyst/kpop/matchers.rb +11 -40
- metadata +8 -19
- data/app/assets/stylesheets/katalyst/kpop/_frame.scss +0 -90
- data/app/assets/stylesheets/katalyst/kpop/_modal.scss +0 -88
- data/app/assets/stylesheets/katalyst/kpop/_scrim.scss +0 -46
- data/app/assets/stylesheets/katalyst/kpop/_side_panel.scss +0 -64
- data/app/assets/stylesheets/katalyst/kpop/_variables.scss +0 -24
- data/app/assets/stylesheets/katalyst/kpop.scss +0 -6
- data/app/components/kpop/modal/footer_component.rb +0 -21
- data/app/components/kpop/modal/header_component.rb +0 -21
- data/app/components/kpop/modal/title_component.html.erb +0 -6
- data/app/components/kpop/modal/title_component.rb +0 -28
- data/app/components/scrim_component.rb +0 -32
- data/app/helpers/kpop_helper.rb +0 -32
- data/app/javascript/kpop/controllers/modal_controller.js +0 -30
- data/app/javascript/kpop/controllers/scrim_controller.js +0 -159
- data/app/javascript/kpop/debug.js +0 -3
- data/app/javascript/kpop/turbo_actions.js +0 -46
- data/app/javascript/kpop/utils/stream_renderer.js +0 -15
- data/lib/katalyst/kpop/turbo.rb +0 -49
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
@use "variables" as *;
|
|
2
|
-
|
|
3
|
-
.kpop-modal {
|
|
4
|
-
display: grid;
|
|
5
|
-
grid-template-areas:
|
|
6
|
-
"title-bar"
|
|
7
|
-
"header"
|
|
8
|
-
"content"
|
|
9
|
-
"footer";
|
|
10
|
-
grid-template-rows: auto auto 1fr auto;
|
|
11
|
-
|
|
12
|
-
background-color: white;
|
|
13
|
-
border-radius: $border-radius;
|
|
14
|
-
overflow: hidden;
|
|
15
|
-
max-height: var(--max-height);
|
|
16
|
-
box-shadow:
|
|
17
|
-
rgb(0 0 0 / 25%) 0 1px 2px,
|
|
18
|
-
rgb(0 0 0 / 31%) 0 0 5px;
|
|
19
|
-
|
|
20
|
-
.kpop-title-bar {
|
|
21
|
-
grid-area: title-bar;
|
|
22
|
-
display: grid;
|
|
23
|
-
grid-template-areas: "close title empty";
|
|
24
|
-
grid-template-columns: 3.5rem auto 3.5rem;
|
|
25
|
-
border-bottom: 1px solid $keyline-color;
|
|
26
|
-
min-height: 3.5rem;
|
|
27
|
-
align-items: center;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
.kpop-header {
|
|
31
|
-
grid-area: header;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
.kpop-content {
|
|
35
|
-
grid-area: content;
|
|
36
|
-
display: flex;
|
|
37
|
-
flex-direction: column;
|
|
38
|
-
overflow: auto;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
.kpop-footer {
|
|
42
|
-
grid-area: footer;
|
|
43
|
-
border-top: 1px solid $keyline-color;
|
|
44
|
-
padding: $default-padding;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
.kpop-title {
|
|
48
|
-
grid-area: title;
|
|
49
|
-
font-weight: bold;
|
|
50
|
-
text-align: center;
|
|
51
|
-
white-space: nowrap;
|
|
52
|
-
overflow: hidden;
|
|
53
|
-
text-overflow: ellipsis;
|
|
54
|
-
line-height: 3.5rem;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
.kpop-close {
|
|
58
|
-
grid-area: close;
|
|
59
|
-
text-align: center;
|
|
60
|
-
background: none;
|
|
61
|
-
border: none;
|
|
62
|
-
display: block;
|
|
63
|
-
font-size: 2rem;
|
|
64
|
-
font-weight: 300;
|
|
65
|
-
text-decoration: none;
|
|
66
|
-
line-height: 3.5rem;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
.button-set {
|
|
70
|
-
display: flex;
|
|
71
|
-
gap: var(--gap, 0.5rem);
|
|
72
|
-
justify-content: flex-end;
|
|
73
|
-
align-items: baseline;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
&.iframe {
|
|
77
|
-
.kpop-content {
|
|
78
|
-
overflow: unset;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
iframe {
|
|
82
|
-
height: var(--max-height);
|
|
83
|
-
width: var(--max-width);
|
|
84
|
-
flex-grow: 1;
|
|
85
|
-
overflow: scroll;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
@use "variables" as *;
|
|
2
|
-
|
|
3
|
-
.scrim {
|
|
4
|
-
position: fixed;
|
|
5
|
-
top: 0;
|
|
6
|
-
bottom: 0;
|
|
7
|
-
left: 0;
|
|
8
|
-
right: 0;
|
|
9
|
-
background: $scrim-background;
|
|
10
|
-
z-index: -1;
|
|
11
|
-
opacity: 0;
|
|
12
|
-
|
|
13
|
-
&[data-hide-animating] {
|
|
14
|
-
animation: fade-out;
|
|
15
|
-
animation-duration: $duration;
|
|
16
|
-
animation-fill-mode: forwards;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
&[data-show-animating] {
|
|
20
|
-
animation: fade-in;
|
|
21
|
-
animation-duration: $duration;
|
|
22
|
-
animation-fill-mode: forwards;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
.scrim[data-scrim-open-value="true"] {
|
|
27
|
-
opacity: 1;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
@keyframes fade-in {
|
|
31
|
-
0% {
|
|
32
|
-
opacity: 0;
|
|
33
|
-
}
|
|
34
|
-
100% {
|
|
35
|
-
opacity: 1;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
@keyframes fade-out {
|
|
40
|
-
0% {
|
|
41
|
-
opacity: 1;
|
|
42
|
-
}
|
|
43
|
-
100% {
|
|
44
|
-
opacity: 0;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
@use "variables" as *;
|
|
2
|
-
|
|
3
|
-
.kpop--frame.side-panel {
|
|
4
|
-
--opening-animation: slide-in-right;
|
|
5
|
-
--closing-animation: slide-out-right;
|
|
6
|
-
--min-width: 35dvw;
|
|
7
|
-
--max-width: calc(100dvw - 4rem);
|
|
8
|
-
--min-height: 100dvh;
|
|
9
|
-
--max-height: 100dvh;
|
|
10
|
-
|
|
11
|
-
margin-inline: auto 0;
|
|
12
|
-
align-self: flex-end;
|
|
13
|
-
|
|
14
|
-
@include mobile {
|
|
15
|
-
& {
|
|
16
|
-
--opening-animation: slide-in-bottom;
|
|
17
|
-
--closing-animation: slide-out-bottom;
|
|
18
|
-
--min-width: 100dvw;
|
|
19
|
-
--max-width: 100dvw;
|
|
20
|
-
--min-height: 50dvh;
|
|
21
|
-
--max-height: calc(100dvh - 1.5rem);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
.kpop-modal {
|
|
26
|
-
border-radius: 0;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
@keyframes slide-in-right {
|
|
31
|
-
0% {
|
|
32
|
-
transform: translateX(100%);
|
|
33
|
-
}
|
|
34
|
-
100% {
|
|
35
|
-
transform: translateX(0%);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
@keyframes slide-out-right {
|
|
40
|
-
0% {
|
|
41
|
-
transform: translateX(0%);
|
|
42
|
-
}
|
|
43
|
-
100% {
|
|
44
|
-
transform: translateX(100%);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
@keyframes slide-in-bottom {
|
|
49
|
-
0% {
|
|
50
|
-
transform: translateY(100%);
|
|
51
|
-
}
|
|
52
|
-
100% {
|
|
53
|
-
transform: translateY(0%);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
@keyframes slide-out-bottom {
|
|
58
|
-
0% {
|
|
59
|
-
transform: translateY(0%);
|
|
60
|
-
}
|
|
61
|
-
100% {
|
|
62
|
-
transform: translateY(100%);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
// frame variables
|
|
2
|
-
$min-width: 35rem !default;
|
|
3
|
-
$max-width: 52rem !default;
|
|
4
|
-
$min-height: 0 !default;
|
|
5
|
-
$max-height: 80dvh !default;
|
|
6
|
-
$duration: 0.2s !default;
|
|
7
|
-
|
|
8
|
-
// breakpoints
|
|
9
|
-
$mobile-width: 600px !default;
|
|
10
|
-
$mobile-height: 400px !default;
|
|
11
|
-
|
|
12
|
-
@mixin mobile {
|
|
13
|
-
@media (max-width: $mobile-width), (max-height: $mobile-height) {
|
|
14
|
-
@content;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// modal variables
|
|
19
|
-
$border-radius: 0.5rem !default;
|
|
20
|
-
$default-padding: 1rem 1.5rem !default;
|
|
21
|
-
$keyline-color: #e0e0e0 !default;
|
|
22
|
-
|
|
23
|
-
// scrim variables
|
|
24
|
-
$scrim-background: rgba(0, 0, 0, 0.6) !default;
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Kpop
|
|
4
|
-
module Modal
|
|
5
|
-
class FooterComponent < ViewComponent::Base
|
|
6
|
-
include Katalyst::HtmlAttributes
|
|
7
|
-
|
|
8
|
-
def call
|
|
9
|
-
tag.div(content, **html_attributes)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def inspect
|
|
13
|
-
"#<#{self.class.name}>"
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def default_html_attributes
|
|
17
|
-
{ class: "kpop-footer" }
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Kpop
|
|
4
|
-
module Modal
|
|
5
|
-
class HeaderComponent < ViewComponent::Base
|
|
6
|
-
include Katalyst::HtmlAttributes
|
|
7
|
-
|
|
8
|
-
def call
|
|
9
|
-
tag.div(content, **html_attributes)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def inspect
|
|
13
|
-
"#<#{self.class.name}>"
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def default_html_attributes
|
|
17
|
-
{ class: "kpop-header" }
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Kpop
|
|
4
|
-
module Modal
|
|
5
|
-
class TitleComponent < ViewComponent::Base
|
|
6
|
-
include Katalyst::HtmlAttributes
|
|
7
|
-
|
|
8
|
-
def initialize(title: nil, captive: false, **)
|
|
9
|
-
super(**)
|
|
10
|
-
|
|
11
|
-
@title = title
|
|
12
|
-
@captive = captive
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def title
|
|
16
|
-
content? ? content : @title
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def captive?
|
|
20
|
-
@captive
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def inspect
|
|
24
|
-
"#<#{self.class.name} title: #{title.inspect}>"
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class ScrimComponent < ViewComponent::Base
|
|
4
|
-
attr_reader :id, :z_index
|
|
5
|
-
|
|
6
|
-
ACTIONS = %w[
|
|
7
|
-
click->scrim#dismiss
|
|
8
|
-
keyup@window->scrim#escape
|
|
9
|
-
].freeze
|
|
10
|
-
|
|
11
|
-
def initialize(id: "scrim", z_index: 40)
|
|
12
|
-
super()
|
|
13
|
-
|
|
14
|
-
@id = id
|
|
15
|
-
@z_index = z_index
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def call
|
|
19
|
-
tag.div(id:,
|
|
20
|
-
class: "scrim",
|
|
21
|
-
data: {
|
|
22
|
-
controller: "scrim",
|
|
23
|
-
scrim_z_index_value: z_index,
|
|
24
|
-
turbo_permanent: "",
|
|
25
|
-
action: ACTIONS.join(" "),
|
|
26
|
-
})
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def inspect
|
|
30
|
-
"#<#{self.class.name} id: #{id.inspect}>"
|
|
31
|
-
end
|
|
32
|
-
end
|
data/app/helpers/kpop_helper.rb
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module KpopHelper
|
|
4
|
-
using HTMLAttributesUtils
|
|
5
|
-
|
|
6
|
-
# Renders a link that will navigate the kpop turbo frame to the given URL.
|
|
7
|
-
# The URL should render a modal response inside a kpop frame tag.
|
|
8
|
-
def kpop_link_to(name = nil, options = nil, html_attributes = nil, &block)
|
|
9
|
-
default_html_attributes = { data: { turbo_frame: "kpop" } }
|
|
10
|
-
if block
|
|
11
|
-
# Param[name] is the path for the link
|
|
12
|
-
link_to(name, default_html_attributes.deep_merge_html_attributes(options || {}), &block)
|
|
13
|
-
else
|
|
14
|
-
link_to(name, options, default_html_attributes.deep_merge_html_attributes(html_attributes || {}))
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# Renders a button that will navigate the kpop turbo frame to the given URL.
|
|
19
|
-
# The URL should render a modal response inside a kpop frame tag.
|
|
20
|
-
def kpop_button_to(name = nil, options = nil, html_attributes = nil, &)
|
|
21
|
-
default_html_attributes = {
|
|
22
|
-
form: { data: { turbo_frame: "kpop" } },
|
|
23
|
-
}
|
|
24
|
-
button_to(name, options, default_html_attributes.deep_merge_html_attributes(html_attributes || {}), &)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# Renders a button that will close the current kpop modal, if any.
|
|
28
|
-
def kpop_button_close(content = nil, **, &block)
|
|
29
|
-
content = capture(yield) if block
|
|
30
|
-
tag.button(content, data: { action: "click->kpop--frame#dismiss:prevent" }, **)
|
|
31
|
-
end
|
|
32
|
-
end
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { Controller } from "@hotwired/stimulus";
|
|
2
|
-
|
|
3
|
-
import DEBUG from "../debug";
|
|
4
|
-
|
|
5
|
-
export default class Kpop__ModalController extends Controller {
|
|
6
|
-
static values = {
|
|
7
|
-
fallback_location: String,
|
|
8
|
-
layout: String,
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
connect() {
|
|
12
|
-
this.debug("connect");
|
|
13
|
-
|
|
14
|
-
if (this.layoutValue) {
|
|
15
|
-
document.querySelector("#kpop").classList.toggle(this.layoutValue, true);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
disconnect() {
|
|
20
|
-
this.debug("disconnect");
|
|
21
|
-
|
|
22
|
-
if (this.layoutValue) {
|
|
23
|
-
document.querySelector("#kpop").classList.toggle(this.layoutValue, false);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
debug(event, ...args) {
|
|
28
|
-
if (DEBUG) console.debug(`ModalController:${event}`, ...args);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import { Controller } from "@hotwired/stimulus";
|
|
2
|
-
|
|
3
|
-
import DEBUG from "../debug";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Scrim controller wraps an element that creates a whole page layer.
|
|
7
|
-
* It is intended to be used behind a modal or nav drawer.
|
|
8
|
-
*
|
|
9
|
-
* If the Scrim element receives a click event, it automatically triggers "scrim:hide".
|
|
10
|
-
*
|
|
11
|
-
* You can show and hide the scrim programmatically by calling show/hide on the controller, e.g. using an outlet.
|
|
12
|
-
*
|
|
13
|
-
* If you need to respond to the scrim showing or hiding you should subscribe to "scrim:show" and "scrim:hide".
|
|
14
|
-
*/
|
|
15
|
-
export default class ScrimController extends Controller {
|
|
16
|
-
static values = {
|
|
17
|
-
open: Boolean,
|
|
18
|
-
captive: Boolean,
|
|
19
|
-
zIndex: Number,
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
connect() {
|
|
23
|
-
if (DEBUG) console.debug("scrim:connect");
|
|
24
|
-
|
|
25
|
-
this.defaultZIndexValue = this.zIndexValue;
|
|
26
|
-
this.defaultCaptiveValue = this.captiveValue;
|
|
27
|
-
|
|
28
|
-
this.element.scrim = this;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
disconnect() {
|
|
32
|
-
if (DEBUG) console.debug("scrim:disconnect");
|
|
33
|
-
|
|
34
|
-
delete this.element.scrim;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async show({
|
|
38
|
-
captive = this.defaultCaptiveValue,
|
|
39
|
-
zIndex = this.defaultZIndexValue,
|
|
40
|
-
top = window.scrollY,
|
|
41
|
-
animate = true,
|
|
42
|
-
} = {}) {
|
|
43
|
-
if (DEBUG) console.debug("scrim:before-show");
|
|
44
|
-
|
|
45
|
-
// hide the scrim before opening the new one if it's already open
|
|
46
|
-
if (this.openValue) {
|
|
47
|
-
await this.hide({ animate });
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// update internal state
|
|
51
|
-
this.openValue = true;
|
|
52
|
-
|
|
53
|
-
// notify listeners of pending request
|
|
54
|
-
this.dispatch("show", { bubbles: true });
|
|
55
|
-
|
|
56
|
-
if (DEBUG) console.debug("scrim:show-start");
|
|
57
|
-
|
|
58
|
-
// update state, perform style updates
|
|
59
|
-
this.#show(captive, zIndex, top);
|
|
60
|
-
|
|
61
|
-
if (animate) {
|
|
62
|
-
// animate opening
|
|
63
|
-
// this will trigger an animationEnd event via CSS that completes the open
|
|
64
|
-
this.element.dataset.showAnimating = "";
|
|
65
|
-
|
|
66
|
-
await new Promise((resolve) => {
|
|
67
|
-
this.element.addEventListener("animationend", () => resolve(), {
|
|
68
|
-
once: true,
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
delete this.element.dataset.showAnimating;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (DEBUG) console.debug("scrim:show-end");
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async hide({ animate = true } = {}) {
|
|
79
|
-
if (!this.openValue || this.element.dataset.hideAnimating) return;
|
|
80
|
-
|
|
81
|
-
if (DEBUG) console.debug("scrim:before-hide");
|
|
82
|
-
|
|
83
|
-
// notify listeners of pending request
|
|
84
|
-
this.dispatch("hide", { bubbles: true });
|
|
85
|
-
|
|
86
|
-
if (DEBUG) console.debug("scrim:hide-start");
|
|
87
|
-
|
|
88
|
-
if (animate) {
|
|
89
|
-
// set animation state
|
|
90
|
-
// this will trigger an animationEnd event via CSS that completes the hide
|
|
91
|
-
this.element.dataset.hideAnimating = "";
|
|
92
|
-
|
|
93
|
-
await new Promise((resolve) => {
|
|
94
|
-
this.element.addEventListener("animationend", () => resolve(), {
|
|
95
|
-
once: true,
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
delete this.element.dataset.hideAnimating;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
this.#hide();
|
|
103
|
-
|
|
104
|
-
this.openValue = false;
|
|
105
|
-
|
|
106
|
-
if (DEBUG) console.debug("scrim:hide-end");
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
dismiss(event) {
|
|
110
|
-
if (DEBUG) console.debug("scrim:dismiss");
|
|
111
|
-
|
|
112
|
-
if (!this.captiveValue) this.dispatch("dismiss", { bubbles: true });
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
escape(event) {
|
|
116
|
-
if (
|
|
117
|
-
event.key === "Escape" &&
|
|
118
|
-
!this.captiveValue &&
|
|
119
|
-
!event.defaultPrevented
|
|
120
|
-
) {
|
|
121
|
-
this.dispatch("dismiss", { bubbles: true });
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Clips body to viewport size and sets the z-index
|
|
127
|
-
*/
|
|
128
|
-
#show(captive, zIndex, top) {
|
|
129
|
-
this.captiveValue = captive;
|
|
130
|
-
this.zIndexValue = zIndex;
|
|
131
|
-
this.scrollY = top;
|
|
132
|
-
|
|
133
|
-
this.element.style.zIndex = this.zIndexValue;
|
|
134
|
-
document.body.style.top = `-${top}px`;
|
|
135
|
-
document.body.style.position = "fixed";
|
|
136
|
-
document.body.style.paddingRight = `-${this.scrollPadding}px`;
|
|
137
|
-
|
|
138
|
-
if (document.body.scrollHeight > window.innerHeight) {
|
|
139
|
-
document.body.style.overflowY = "scroll";
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Unclips body from viewport size and unsets the z-index
|
|
145
|
-
*/
|
|
146
|
-
#hide() {
|
|
147
|
-
this.captiveValue = this.defaultCaptiveValue;
|
|
148
|
-
this.zIndexValue = this.defaultZIndexValue;
|
|
149
|
-
|
|
150
|
-
this.element.style.removeProperty("z-index");
|
|
151
|
-
document.body.style.removeProperty("position");
|
|
152
|
-
document.body.style.removeProperty("top");
|
|
153
|
-
document.body.style.removeProperty("overflow-y");
|
|
154
|
-
|
|
155
|
-
window.scrollTo({ left: 0, top: this.scrollY, behavior: "instant" });
|
|
156
|
-
|
|
157
|
-
delete this.scrollY;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { Turbo } from "@hotwired/turbo-rails";
|
|
2
|
-
|
|
3
|
-
import DEBUG from "./debug";
|
|
4
|
-
|
|
5
|
-
import { StreamModal } from "./modals/stream_modal";
|
|
6
|
-
import { StreamRenderer } from "./utils/stream_renderer";
|
|
7
|
-
|
|
8
|
-
function kpop(action) {
|
|
9
|
-
return action.targetElements[0]?.kpop;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
Turbo.StreamActions.kpop_open = function () {
|
|
13
|
-
const animate = !kpop(this).openValue;
|
|
14
|
-
|
|
15
|
-
kpop(this)
|
|
16
|
-
?.dismiss({ animate, reason: "before-turbo-stream" })
|
|
17
|
-
.then(() => {
|
|
18
|
-
new StreamRenderer(this.targetElements[0], this).render();
|
|
19
|
-
kpop(this)?.open(new StreamModal(this.target, this), { animate });
|
|
20
|
-
});
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
Turbo.StreamActions.kpop_dismiss = function () {
|
|
24
|
-
kpop(this)?.dismiss({ reason: "turbo_stream.kpop.dismiss" });
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
Turbo.StreamActions.kpop_redirect_to = function () {
|
|
28
|
-
if (this.dataset.turboFrame === this.target) {
|
|
29
|
-
if (DEBUG)
|
|
30
|
-
console.debug(
|
|
31
|
-
`kpop: redirecting ${this.target} to ${this.getAttribute("href")}`,
|
|
32
|
-
);
|
|
33
|
-
const a = document.createElement("A");
|
|
34
|
-
a.setAttribute("data-turbo-action", "replace");
|
|
35
|
-
this.targetElements[0].delegate.linkClickIntercepted(
|
|
36
|
-
a,
|
|
37
|
-
this.getAttribute("href"),
|
|
38
|
-
);
|
|
39
|
-
} else {
|
|
40
|
-
if (DEBUG)
|
|
41
|
-
console.debug(`kpop: redirecting to ${this.getAttribute("href")}`);
|
|
42
|
-
Turbo.visit(this.getAttribute("href"), {
|
|
43
|
-
action: this.dataset.turboAction,
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import DEBUG from "../debug";
|
|
2
|
-
|
|
3
|
-
export class StreamRenderer {
|
|
4
|
-
constructor(frame, action) {
|
|
5
|
-
this.frame = frame;
|
|
6
|
-
this.action = action;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
render() {
|
|
10
|
-
if (DEBUG) console.debug("stream-renderer:render");
|
|
11
|
-
this.frame.src = "";
|
|
12
|
-
this.frame.innerHTML = "";
|
|
13
|
-
this.frame.append(this.action.templateContent);
|
|
14
|
-
}
|
|
15
|
-
}
|
data/lib/katalyst/kpop/turbo.rb
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Katalyst
|
|
4
|
-
module Kpop
|
|
5
|
-
module Turbo
|
|
6
|
-
class TagBuilder
|
|
7
|
-
delegate :action, :turbo_stream_action_tag, to: :@builder
|
|
8
|
-
|
|
9
|
-
def initialize(builder)
|
|
10
|
-
@builder = builder
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
# Open a modal in the kpop frame identified by <tt>id</tt> either the <tt>content</tt> passed in or a
|
|
14
|
-
# rendering result determined by the <tt>rendering</tt> keyword arguments, the content in the block,
|
|
15
|
-
# or the rendering of the content as a record. Examples:
|
|
16
|
-
#
|
|
17
|
-
# <%= turbo_stream.kpop.open modal %>
|
|
18
|
-
# <%= turbo_stream.kpop.open partial: "modals/modal", locals: { record: } %>
|
|
19
|
-
# <%= turbo_stream.kpop.open do %>
|
|
20
|
-
# <%= render Kpop::ModalComponent.new(title: "Example") do %>
|
|
21
|
-
# ...
|
|
22
|
-
# <% end %>
|
|
23
|
-
# <% end %>
|
|
24
|
-
def open(content = nil, id: "kpop", **, &)
|
|
25
|
-
action(:kpop_open, id, content, **, &)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# Render a turbo stream action that will dismiss any open kpop modal.
|
|
29
|
-
def dismiss(id: "kpop")
|
|
30
|
-
turbo_stream_action_tag(:kpop_dismiss, target: id)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# Renders a kpop redirect controller response that will escape the frame and navigate to the given URL.
|
|
34
|
-
# Note: turbo does not currently snapshot page history accurately when using "advance" (Oct 23).
|
|
35
|
-
def redirect_to(href, id: "kpop", action: "replace", target: nil)
|
|
36
|
-
turbo_stream_action_tag(
|
|
37
|
-
:kpop_redirect_to,
|
|
38
|
-
target: id,
|
|
39
|
-
href:,
|
|
40
|
-
data: {
|
|
41
|
-
turbo_action: action,
|
|
42
|
-
turbo_frame: target,
|
|
43
|
-
},
|
|
44
|
-
)
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|