katalyst-kpop 2.0.9 → 3.0.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +17 -43
- data/app/assets/builds/katalyst/kpop.esm.js +599 -0
- data/app/assets/builds/katalyst/kpop.js +479 -519
- data/app/assets/builds/katalyst/kpop.min.js +2 -1
- data/app/assets/builds/katalyst/kpop.min.js.map +1 -0
- data/app/assets/builds/katalyst/kpop.umd.js +5890 -0
- data/app/assets/config/kpop.js +1 -1
- data/app/assets/stylesheets/katalyst/kpop/_frame.scss +104 -0
- data/app/assets/stylesheets/katalyst/kpop/_modal.scss +95 -0
- data/app/assets/stylesheets/katalyst/kpop/_scrim.scss +33 -3
- data/app/assets/stylesheets/katalyst/kpop/_side_panel.scss +64 -0
- data/app/assets/stylesheets/katalyst/kpop/_variables.scss +25 -0
- data/app/assets/stylesheets/katalyst/kpop.scss +6 -1
- data/app/components/concerns/kpop/has_html_attributes.rb +78 -0
- data/app/components/kpop/frame_component.html.erb +14 -0
- data/app/components/kpop/frame_component.rb +45 -0
- data/app/components/kpop/modal/title_component.html.erb +6 -0
- data/app/components/kpop/modal/title_component.rb +28 -0
- data/app/components/kpop/modal_component.html.erb +8 -0
- data/app/components/kpop/modal_component.rb +39 -0
- data/app/components/scrim_component.rb +32 -0
- data/app/helpers/kpop_helper.rb +12 -35
- data/app/javascript/kpop/application.js +15 -0
- data/app/javascript/kpop/controllers/close_controller.js +9 -0
- data/app/javascript/kpop/controllers/frame_controller.js +189 -0
- data/app/javascript/kpop/controllers/modal_controller.js +30 -0
- data/app/javascript/kpop/controllers/redirect_controller.js +22 -0
- data/app/{assets/javascripts → javascript/kpop}/controllers/scrim_controller.js +76 -72
- data/app/javascript/kpop/debug.js +3 -0
- data/app/javascript/kpop/modals/content_modal.js +46 -0
- data/app/javascript/kpop/modals/frame_modal.js +41 -0
- data/app/javascript/kpop/modals/modal.js +69 -0
- data/app/javascript/kpop/modals/stream_modal.js +49 -0
- data/app/javascript/kpop/modals/stream_renderer.js +15 -0
- data/app/views/layouts/kpop.html.erb +1 -1
- data/config/importmap.rb +1 -4
- data/lib/katalyst/kpop/engine.rb +13 -12
- data/lib/katalyst/kpop/matchers/base.rb +18 -0
- data/lib/katalyst/kpop/matchers/capybara_matcher.rb +46 -0
- data/lib/katalyst/kpop/matchers/capybara_parser.rb +17 -0
- data/lib/katalyst/kpop/matchers/chained_matcher.rb +40 -0
- data/lib/katalyst/kpop/matchers/frame_matcher.rb +16 -0
- data/lib/katalyst/kpop/matchers/modal_matcher.rb +20 -0
- data/lib/katalyst/kpop/matchers/redirect_finder.rb +16 -0
- data/lib/katalyst/kpop/matchers/redirect_matcher.rb +28 -0
- data/lib/katalyst/kpop/matchers/response_matcher.rb +33 -0
- data/lib/katalyst/kpop/matchers/stream_matcher.rb +16 -0
- data/lib/katalyst/kpop/matchers/title_finder.rb +16 -0
- data/lib/katalyst/kpop/matchers/title_matcher.rb +28 -0
- data/lib/katalyst/kpop/matchers.rb +79 -0
- data/lib/katalyst/kpop/turbo.rb +56 -0
- data/lib/katalyst/kpop/version.rb +1 -1
- data/lib/katalyst/kpop.rb +4 -0
- metadata +90 -15
- data/app/assets/builds/katalyst/kpop.css +0 -117
- data/app/assets/javascripts/controllers/kpop_controller.js +0 -72
- data/app/assets/javascripts/katalyst/kpop.js +0 -9
- data/app/assets/stylesheets/katalyst/kpop/_index.scss +0 -2
- data/app/assets/stylesheets/katalyst/kpop/_kpop.scss +0 -133
- data/app/helpers/kpop/modal.rb +0 -98
- data/app/helpers/scrim_helper.rb +0 -13
@@ -1,117 +0,0 @@
|
|
1
|
-
.kpop-container {
|
2
|
-
display: none;
|
3
|
-
position: fixed;
|
4
|
-
left: 0;
|
5
|
-
top: 0;
|
6
|
-
right: 0;
|
7
|
-
bottom: 0;
|
8
|
-
justify-content: center;
|
9
|
-
align-items: center;
|
10
|
-
z-index: 1000;
|
11
|
-
pointer-events: none;
|
12
|
-
}
|
13
|
-
.kpop-container > * {
|
14
|
-
pointer-events: auto;
|
15
|
-
}
|
16
|
-
|
17
|
-
.kpop-modal {
|
18
|
-
position: relative;
|
19
|
-
overflow: hidden;
|
20
|
-
display: grid;
|
21
|
-
grid-template-areas: "title-bar" "header" "content" "footer";
|
22
|
-
grid-template-rows: auto auto 1fr auto;
|
23
|
-
border: 1px solid black;
|
24
|
-
border-radius: 0.5rem;
|
25
|
-
background-color: white;
|
26
|
-
min-width: 35rem;
|
27
|
-
max-width: 52rem;
|
28
|
-
min-height: 0;
|
29
|
-
max-height: 80vh;
|
30
|
-
}
|
31
|
-
.kpop-modal .kpop-title-bar {
|
32
|
-
grid-area: title-bar;
|
33
|
-
display: flex;
|
34
|
-
background: #344055;
|
35
|
-
color: white;
|
36
|
-
}
|
37
|
-
.kpop-modal .kpop-title-bar .kpop-title {
|
38
|
-
padding: 1rem 1.5rem;
|
39
|
-
flex-grow: 1;
|
40
|
-
}
|
41
|
-
.kpop-modal .kpop-title-bar .kpop-close {
|
42
|
-
background: none;
|
43
|
-
border: none;
|
44
|
-
color: white;
|
45
|
-
cursor: pointer;
|
46
|
-
display: block;
|
47
|
-
font-size: 2rem;
|
48
|
-
font-weight: bold;
|
49
|
-
padding: 0 0.75rem;
|
50
|
-
text-decoration: none;
|
51
|
-
}
|
52
|
-
.kpop-modal .kpop-header {
|
53
|
-
grid-area: header;
|
54
|
-
}
|
55
|
-
.kpop-modal .kpop-content {
|
56
|
-
grid-area: content;
|
57
|
-
display: flex;
|
58
|
-
flex-direction: column;
|
59
|
-
overflow: auto;
|
60
|
-
}
|
61
|
-
.kpop-modal .kpop-footer {
|
62
|
-
grid-area: footer;
|
63
|
-
background: white;
|
64
|
-
border-top: 1px solid black;
|
65
|
-
padding: 1rem 1.5rem;
|
66
|
-
}
|
67
|
-
.kpop-modal .kpop-buttons {
|
68
|
-
display: flex;
|
69
|
-
gap: 0.5rem;
|
70
|
-
justify-content: space-between;
|
71
|
-
}
|
72
|
-
|
73
|
-
.kpop-modal.iframe .kpop-content {
|
74
|
-
overflow: unset;
|
75
|
-
}
|
76
|
-
.kpop-modal.iframe iframe {
|
77
|
-
height: 80vh;
|
78
|
-
width: 52rem;
|
79
|
-
flex-grow: 1;
|
80
|
-
overflow: scroll;
|
81
|
-
}
|
82
|
-
|
83
|
-
@media (max-width: 600px), (max-height: 600px) {
|
84
|
-
.kpop-modal {
|
85
|
-
max-width: unset;
|
86
|
-
min-width: unset;
|
87
|
-
width: 100%;
|
88
|
-
height: 100%;
|
89
|
-
max-height: 100vh;
|
90
|
-
border-radius: 0;
|
91
|
-
border: none;
|
92
|
-
}
|
93
|
-
.kpop-modal.iframe iframe {
|
94
|
-
width: 100%;
|
95
|
-
height: 100%;
|
96
|
-
}
|
97
|
-
.kpop-buttons {
|
98
|
-
flex-direction: column-reverse;
|
99
|
-
text-align: center;
|
100
|
-
}
|
101
|
-
}
|
102
|
-
.scrim {
|
103
|
-
position: fixed;
|
104
|
-
top: 0;
|
105
|
-
bottom: 0;
|
106
|
-
left: 0;
|
107
|
-
right: 0;
|
108
|
-
background: rgba(0, 0, 0, 0.6);
|
109
|
-
z-index: -1;
|
110
|
-
transition: opacity 0.2s ease-in-out, z-index 0.2s step-end;
|
111
|
-
opacity: 0;
|
112
|
-
}
|
113
|
-
|
114
|
-
.scrim[data-scrim-open-value=true] {
|
115
|
-
opacity: 1;
|
116
|
-
transition: opacity 0.2s ease-in-out, z-index 0.2s step-start;
|
117
|
-
}
|
@@ -1,72 +0,0 @@
|
|
1
|
-
import { Controller } from "@hotwired/stimulus";
|
2
|
-
import ScrimController from "controllers/scrim_controller";
|
3
|
-
|
4
|
-
export default class KpopController extends Controller {
|
5
|
-
static targets = ["content", "closeButton"];
|
6
|
-
static values = {
|
7
|
-
open: Boolean,
|
8
|
-
};
|
9
|
-
|
10
|
-
contentTargetConnected(target) {
|
11
|
-
// Set the modal content to temporary to ensure its omitted when caching the page
|
12
|
-
target.setAttribute("data-turbo-temporary", "");
|
13
|
-
|
14
|
-
// When switching modals a target may connect while scrim is already open
|
15
|
-
if (this.openValue) return;
|
16
|
-
|
17
|
-
if (ScrimController.showScrim({ dismiss: this.hasCloseButtonTarget })) {
|
18
|
-
this.openValue = true;
|
19
|
-
} else {
|
20
|
-
this.#clear();
|
21
|
-
}
|
22
|
-
}
|
23
|
-
|
24
|
-
contentTargetDisconnected() {
|
25
|
-
// When switching modals there may still be content to show
|
26
|
-
if (this.hasContentTarget) return;
|
27
|
-
|
28
|
-
this.openValue = false;
|
29
|
-
ScrimController.hideScrim();
|
30
|
-
}
|
31
|
-
|
32
|
-
openValueChanged(open) {
|
33
|
-
this.element.style.display = open ? "flex" : "none";
|
34
|
-
}
|
35
|
-
|
36
|
-
dismiss() {
|
37
|
-
if (!this.hasContentTarget || !this.openValue) return;
|
38
|
-
|
39
|
-
const dismissUrl = this.contentTarget.dataset.dismissUrl;
|
40
|
-
const dismissAction = this.contentTarget.dataset.dismissAction;
|
41
|
-
|
42
|
-
if (dismissUrl) {
|
43
|
-
if (dismissAction === "replace") {
|
44
|
-
if (isSameUrl(document.referrer, dismissUrl)) {
|
45
|
-
// if we came from the same page, send the user back
|
46
|
-
history.back();
|
47
|
-
} else {
|
48
|
-
// if we came from a different page, dismiss the modal and replace url
|
49
|
-
history.replaceState({}, "", dismissUrl);
|
50
|
-
}
|
51
|
-
} else {
|
52
|
-
// default, send the user on to the specified URL
|
53
|
-
window.location.href = dismissUrl;
|
54
|
-
}
|
55
|
-
}
|
56
|
-
|
57
|
-
this.#clear();
|
58
|
-
}
|
59
|
-
|
60
|
-
#clear() {
|
61
|
-
this.element.removeAttribute("src");
|
62
|
-
this.element.innerHTML = "";
|
63
|
-
}
|
64
|
-
}
|
65
|
-
|
66
|
-
function isSameUrl(previous, next) {
|
67
|
-
try {
|
68
|
-
return `${new URL(previous)}` === `${new URL(next, location.href)}`;
|
69
|
-
} catch {
|
70
|
-
return false;
|
71
|
-
}
|
72
|
-
}
|
@@ -1,9 +0,0 @@
|
|
1
|
-
import KpopController from "../controllers/kpop_controller";
|
2
|
-
import ScrimController from "../controllers/scrim_controller";
|
3
|
-
|
4
|
-
const Definitions = [
|
5
|
-
{ identifier: "kpop", controllerConstructor: KpopController },
|
6
|
-
{ identifier: "scrim", controllerConstructor: ScrimController },
|
7
|
-
];
|
8
|
-
|
9
|
-
export { Definitions as default, KpopController, ScrimController };
|
@@ -1,133 +0,0 @@
|
|
1
|
-
$title-background-color: #344055 !default;
|
2
|
-
$title-text-color: white !default;
|
3
|
-
$min-width: 35rem !default;
|
4
|
-
$max-width: 52rem !default;
|
5
|
-
$min-height: 0 !default;
|
6
|
-
$max-height: 80vh !default;
|
7
|
-
$default-padding: 1rem 1.5rem !default;
|
8
|
-
|
9
|
-
.kpop-container {
|
10
|
-
display: none;
|
11
|
-
|
12
|
-
position: fixed;
|
13
|
-
left: 0;
|
14
|
-
top: 0;
|
15
|
-
right: 0;
|
16
|
-
bottom: 0;
|
17
|
-
|
18
|
-
justify-content: center;
|
19
|
-
align-items: center;
|
20
|
-
z-index: 1000;
|
21
|
-
pointer-events: none;
|
22
|
-
|
23
|
-
> * {
|
24
|
-
pointer-events: auto;
|
25
|
-
}
|
26
|
-
}
|
27
|
-
|
28
|
-
.kpop-modal {
|
29
|
-
position: relative;
|
30
|
-
overflow: hidden;
|
31
|
-
|
32
|
-
display: grid;
|
33
|
-
grid-template-areas:
|
34
|
-
"title-bar"
|
35
|
-
"header"
|
36
|
-
"content"
|
37
|
-
"footer";
|
38
|
-
grid-template-rows: auto auto 1fr auto;
|
39
|
-
|
40
|
-
border: 1px solid black;
|
41
|
-
border-radius: 0.5rem;
|
42
|
-
background-color: white;
|
43
|
-
|
44
|
-
min-width: $min-width;
|
45
|
-
max-width: $max-width;
|
46
|
-
min-height: $min-height;
|
47
|
-
max-height: $max-height;
|
48
|
-
|
49
|
-
.kpop-title-bar {
|
50
|
-
grid-area: title-bar;
|
51
|
-
display: flex;
|
52
|
-
background: $title-background-color;
|
53
|
-
color: $title-text-color;
|
54
|
-
|
55
|
-
.kpop-title {
|
56
|
-
padding: $default-padding;
|
57
|
-
flex-grow: 1;
|
58
|
-
}
|
59
|
-
|
60
|
-
.kpop-close {
|
61
|
-
background: none;
|
62
|
-
border: none;
|
63
|
-
color: $title-text-color;
|
64
|
-
cursor: pointer;
|
65
|
-
display: block;
|
66
|
-
font-size: 2rem;
|
67
|
-
font-weight: bold;
|
68
|
-
padding: 0 0.75rem;
|
69
|
-
text-decoration: none;
|
70
|
-
}
|
71
|
-
}
|
72
|
-
|
73
|
-
.kpop-header {
|
74
|
-
grid-area: header;
|
75
|
-
}
|
76
|
-
|
77
|
-
.kpop-content {
|
78
|
-
grid-area: content;
|
79
|
-
display: flex;
|
80
|
-
flex-direction: column;
|
81
|
-
overflow: auto;
|
82
|
-
}
|
83
|
-
|
84
|
-
.kpop-footer {
|
85
|
-
grid-area: footer;
|
86
|
-
background: white;
|
87
|
-
border-top: 1px solid black;
|
88
|
-
padding: $default-padding;
|
89
|
-
}
|
90
|
-
|
91
|
-
.kpop-buttons {
|
92
|
-
display: flex;
|
93
|
-
gap: 0.5rem;
|
94
|
-
justify-content: space-between;
|
95
|
-
}
|
96
|
-
}
|
97
|
-
|
98
|
-
.kpop-modal.iframe {
|
99
|
-
.kpop-content {
|
100
|
-
overflow: unset;
|
101
|
-
}
|
102
|
-
|
103
|
-
iframe {
|
104
|
-
height: $max-height;
|
105
|
-
width: $max-width;
|
106
|
-
flex-grow: 1;
|
107
|
-
overflow: scroll;
|
108
|
-
}
|
109
|
-
}
|
110
|
-
|
111
|
-
@media (max-width: 600px), (max-height: 600px) {
|
112
|
-
.kpop-modal {
|
113
|
-
max-width: unset;
|
114
|
-
min-width: unset;
|
115
|
-
width: 100%;
|
116
|
-
height: 100%;
|
117
|
-
max-height: 100vh;
|
118
|
-
border-radius: 0;
|
119
|
-
border: none;
|
120
|
-
}
|
121
|
-
|
122
|
-
.kpop-modal.iframe {
|
123
|
-
iframe {
|
124
|
-
width: 100%;
|
125
|
-
height: 100%;
|
126
|
-
}
|
127
|
-
}
|
128
|
-
|
129
|
-
.kpop-buttons {
|
130
|
-
flex-direction: column-reverse;
|
131
|
-
text-align: center;
|
132
|
-
}
|
133
|
-
}
|
data/app/helpers/kpop/modal.rb
DELETED
@@ -1,98 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# rubocop:disable Rails/HelperInstanceVariable
|
4
|
-
module Kpop
|
5
|
-
class Modal
|
6
|
-
delegate_missing_to :@context
|
7
|
-
|
8
|
-
def initialize(context)
|
9
|
-
@context = context
|
10
|
-
end
|
11
|
-
|
12
|
-
def render(options = {})
|
13
|
-
dom_class = options.delete(:class)
|
14
|
-
|
15
|
-
# Generate a title bar. This can be overridden by calling title_bar again.
|
16
|
-
title_bar(options) unless options.fetch(:title, "").nil?
|
17
|
-
|
18
|
-
# Render block. This may have side-effect writes to header/content/footer
|
19
|
-
# etc. If @content is set then this value will be ignored.
|
20
|
-
content = capture do
|
21
|
-
yield self
|
22
|
-
end
|
23
|
-
|
24
|
-
tag.div(class: class_names("kpop-modal", dom_class),
|
25
|
-
data: kpop_data_options(options),
|
26
|
-
**options) do
|
27
|
-
concat @title_bar
|
28
|
-
concat @header if @header.present?
|
29
|
-
concat @content.presence || tag.div(content, class: "kpop-content")
|
30
|
-
concat @footer if @footer.present?
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# Generates a sticky title bar for the modal. Content should not be too long
|
35
|
-
# as the bar does not provide wrapping.
|
36
|
-
def title_bar(options = {}, &block)
|
37
|
-
title = options.delete(:title)
|
38
|
-
captive = options.delete(:captive)
|
39
|
-
@title_bar = tag.div(class: "kpop-title-bar", **options) do
|
40
|
-
concat(tag.span(class: "kpop-title") do
|
41
|
-
concat(block ? (yield self) : title)
|
42
|
-
end)
|
43
|
-
concat(close_icon) unless captive
|
44
|
-
end
|
45
|
-
nil
|
46
|
-
end
|
47
|
-
|
48
|
-
# Generates sticky header content for the top of the modal. Content is not
|
49
|
-
# padded, if you want padding you should provide a padding class.
|
50
|
-
def header(**options, &block)
|
51
|
-
modal_content(:header, **options, &block)
|
52
|
-
end
|
53
|
-
|
54
|
-
# Generates content for the modal. Content is not padded, if you want
|
55
|
-
# padding you should provide a padding class.
|
56
|
-
def content(**options, &block)
|
57
|
-
modal_content(:content, **options, &block)
|
58
|
-
end
|
59
|
-
|
60
|
-
# Generates a sticky footer element at the bottom of the modal.
|
61
|
-
# Footer is padded and contents are assumed to be buttons.
|
62
|
-
def footer(**options, &block)
|
63
|
-
modal_content(:footer, **options, &block)
|
64
|
-
end
|
65
|
-
|
66
|
-
def close_icon
|
67
|
-
tag.button(
|
68
|
-
"×",
|
69
|
-
class: "kpop-close",
|
70
|
-
data: {
|
71
|
-
kpop_target: "closeButton",
|
72
|
-
action: "click->kpop#dismiss:prevent",
|
73
|
-
},
|
74
|
-
)
|
75
|
-
end
|
76
|
-
|
77
|
-
private
|
78
|
-
|
79
|
-
def kpop_data_options(options)
|
80
|
-
data = options.delete(:data) || {}
|
81
|
-
data.reverse_merge(
|
82
|
-
kpop_target: "content",
|
83
|
-
dismiss_action: options.delete(:dismiss_action),
|
84
|
-
dismiss_url: options.delete(:dismiss_url),
|
85
|
-
)
|
86
|
-
end
|
87
|
-
|
88
|
-
def class_for(name, options)
|
89
|
-
class_names("kpop-#{name}", options.delete(:class))
|
90
|
-
end
|
91
|
-
|
92
|
-
def modal_content(name, **options, &block)
|
93
|
-
instance_variable_set("@#{name}", tag.div(class: class_for(name, options), **options, &block))
|
94
|
-
nil
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
# rubocop:enable Rails/HelperInstanceVariable
|
data/app/helpers/scrim_helper.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ScrimHelper
|
4
|
-
def scrim_tag(z_index: 40)
|
5
|
-
tag.div(class: "scrim", data: { controller: "scrim", scrim_z_index_value: z_index, action: <<~ACTIONS })
|
6
|
-
click->scrim#dismiss
|
7
|
-
keyup@window->scrim#escape
|
8
|
-
scrim:request:hide@window->scrim#hide
|
9
|
-
scrim:request:show@window->scrim#show
|
10
|
-
turbo:before-cache@document->scrim#hide
|
11
|
-
ACTIONS
|
12
|
-
end
|
13
|
-
end
|