coveragebook_components 0.6.5 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,25 @@
1
+ <% if render_as_modal? %>
2
+ <%= turbo_frame_tag coco_modal_frame_id(name), class: "modal-frame" do %>
3
+ <%= render component_tag(
4
+ id: id,
5
+ role: "dialog",
6
+ aria: {modal: "true"},
7
+ data: {turbo_temporary: true},
8
+ x: {
9
+ data: x_data("modal"),
10
+ bind: "root",
11
+ cloak: true,
12
+ },
13
+ ) do %>
14
+ <div class="modal-overlay" x-show="open" x-transition.opacity></div>
15
+ <div class="modal-container" x-show="open" x-transition>
16
+ <div class="modal-content" x-trap.noscroll.inert.noreturn="open">
17
+ <%= modal_content %>
18
+ </div>
19
+ </div>
20
+ <% end %>
21
+ <%= render_flash_messages %>
22
+ <% end %>
23
+ <% else %>
24
+ <%= content %>
25
+ <% end %>
@@ -0,0 +1,54 @@
1
+ import { CocoComponent } from "@js/coco";
2
+
3
+ export default CocoComponent("modal", () => {
4
+ return {
5
+ open: false,
6
+ frame: null,
7
+ options: ["dismissable", "closeOnSubmit"],
8
+
9
+ init() {
10
+ this.onFrameSubmitEnd = this.onFrameSubmitEnd.bind(this);
11
+
12
+ this.frame = this.$el.closest("turbo-frame");
13
+ this.frame.addEventListener("turbo:submit-end", this.onFrameSubmitEnd);
14
+
15
+ this.$nextTick(() => this.show()); // ensure transitions run
16
+ },
17
+
18
+ show() {
19
+ this.open = true;
20
+ },
21
+
22
+ hide() {
23
+ this.open = false;
24
+ setTimeout(() => this.clearFrame(), 100);
25
+ },
26
+
27
+ dismiss(event) {
28
+ if (this.$options.dismissable) this.hide();
29
+ },
30
+
31
+ clearFrame() {
32
+ this.frame.removeAttribute("src");
33
+ this.frame.removeAttribute("complete");
34
+ this.frame.innerHTML = "";
35
+ },
36
+
37
+ onFrameSubmitEnd() {
38
+ if (this.$options.closeOnSubmit && event.detail.success) {
39
+ this.hide();
40
+ }
41
+ },
42
+
43
+ destroy() {
44
+ this.frame.removeEventListener("turbo:submit-end", this.onFrameSubmitEnd);
45
+ },
46
+
47
+ root: {
48
+ "x-options": "options",
49
+ "x-show": "open",
50
+ "@keydown.escape.document": "dismiss",
51
+ "@modal:hide.document": "hide",
52
+ },
53
+ };
54
+ });
@@ -0,0 +1,52 @@
1
+ module Coco
2
+ class Modal < Coco::Component
3
+ include Concerns::AcceptsOptions
4
+ include Turbo::FramesHelper
5
+
6
+ accepts_option :dismissable, from: [true, false], default: true
7
+ accepts_option :close_on_submit, from: [true, false], default: true
8
+
9
+ renders_one :title
10
+
11
+ renders_one :dialog, ->(**kwargs, &block) do
12
+ @dialog_content = capture { block.call }
13
+ Coco::ModalDialog.new(dismissable: get_option_value(:dismissable), **kwargs)
14
+ end
15
+
16
+ before_render do
17
+ if dialog? && title?
18
+ dialog.with_title { title.to_s }
19
+ end
20
+ end
21
+
22
+ attr_reader :name, :show
23
+
24
+ def initialize(name:, show: false, **kwargs)
25
+ @name = name
26
+ @show = show
27
+ title { kwargs[:title] } if kwargs[:title]
28
+ end
29
+
30
+ def render_as_modal?
31
+ request.headers["Turbo-Frame"].present? || show
32
+ end
33
+
34
+ def id
35
+ "coco-modal-#{name.to_s.dasherize}"
36
+ end
37
+
38
+ def modal_content
39
+ dialog? ? dialog : content
40
+ end
41
+
42
+ def content
43
+ @dialog_content || super
44
+ end
45
+
46
+ def render_flash_messages
47
+ if helpers.respond_to?(:render_turbo_stream_flash_messages)
48
+ helpers.render_turbo_stream_flash_messages
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,28 @@
1
+ @layer components {
2
+ [data-coco][data-component="modal-dialog"] {
3
+ @apply shadow-2xl rounded-xl w-full;
4
+ @apply max-w-2xl; /* temp until sizes added */
5
+
6
+ .modal-dialog-header {
7
+ @apply relative flex items-center justify-center;
8
+ @apply px-8 h-16 border-b border-gray-300 rounded-t-xl bg-white;
9
+ }
10
+
11
+ .modal-dialog-title {
12
+ @apply text-lg pr-6 w-full font-semibold truncate;
13
+ }
14
+
15
+ .modal-dialog-close {
16
+ @apply flex-none block p-2 absolute top-1/2 right-3 -translate-y-1/2;
17
+ @apply focus:ring-0 focus:outline-none text-content-dark-muted hover:text-content-dark-2;
18
+ }
19
+
20
+ .modal-dialog-content {
21
+ @apply px-8 py-6 rounded-xl bg-background-light-3;
22
+ }
23
+
24
+ .modal-dialog-header + .modal-dialog-content {
25
+ @apply rounded-t-none;
26
+ }
27
+ }
28
+ }
@@ -0,0 +1,19 @@
1
+ <%= render component_tag(x: {data: x_data("modalDialog")}) do %>
2
+ <% if header? %>
3
+ <header class="modal-dialog-header">
4
+ <% if title? %>
5
+ <h4 class="modal-dialog-title" data-role="title">
6
+ <%= title %>
7
+ </h4>
8
+ <% end %>
9
+ <% if dismissable? %>
10
+ <button type="button" class="modal-dialog-close" data-role="close" @click="close">
11
+ <%= coco_icon(:x, size: :md) %>
12
+ </button>
13
+ <% end %>
14
+ </header>
15
+ <% end %>
16
+ <div class="modal-dialog-content">
17
+ <%= content %>
18
+ </div>
19
+ <% end %>
@@ -0,0 +1,36 @@
1
+ import { CocoComponent } from "@js/coco";
2
+
3
+ export default CocoComponent("modalDialog", () => {
4
+ return {
5
+ frame: null,
6
+
7
+ init() {
8
+ this.onFrameLoad = this.onFrameLoad.bind(this);
9
+ this.frame = this.$el.closest("turbo-frame");
10
+
11
+ if (this.frame) {
12
+ this.frame.addEventListener("turbo:frame-load", this.onFrameLoad);
13
+ }
14
+ },
15
+
16
+ close() {
17
+ this.$dispatch("modal:hide");
18
+ },
19
+
20
+ onFrameLoad() {
21
+ this.$focus.focus(this.firstInput);
22
+ },
23
+
24
+ destroy() {
25
+ if (this.frame) {
26
+ this.frame.removeEventListener("turbo:frame-load", this.onFrameLoad);
27
+ }
28
+ },
29
+
30
+ get firstInput() {
31
+ return this.$root.querySelector(
32
+ "input:not([type=hidden]), textarea, select"
33
+ );
34
+ },
35
+ };
36
+ });
@@ -0,0 +1,27 @@
1
+ module Coco
2
+ class ModalDialog < Coco::Component
3
+ include Concerns::AcceptsOptions
4
+
5
+ accepts_option :dismissable, from: [true, false], default: true
6
+
7
+ renders_one :title
8
+
9
+ before_render do
10
+ unless title?
11
+ raise ArgumentError, "A title is required for modal dialogs"
12
+ end
13
+ end
14
+
15
+ def initialize(**kwargs)
16
+ title { kwargs[:title] } if kwargs[:title]
17
+ end
18
+
19
+ def header?
20
+ title || dismissable?
21
+ end
22
+
23
+ def dismissable?
24
+ get_option_value(:dismissable)
25
+ end
26
+ end
27
+ end
@@ -1,32 +1,59 @@
1
1
  module Coco
2
2
  module BaseHelper
3
- def coco_tag(*args, **kwargs, &block)
4
- render Coco::Tag.new(*args, **kwargs), &block
3
+ def coco_tag(*, **, &block)
4
+ render Coco::Tag.new(*, **), &block
5
5
  end
6
6
 
7
- def coco_svg(path = nil, **kwargs)
8
- render Coco::Svg.new(path: path, **kwargs)
7
+ def coco_svg(path = nil, **)
8
+ render Coco::Svg.new(path: path, **)
9
9
  end
10
10
 
11
- def coco_image(src = nil, **kwargs)
12
- render Coco::Image.new(src: src, **kwargs)
11
+ def coco_image(src = nil, **)
12
+ render Coco::Image.new(src: src, **)
13
13
  end
14
14
 
15
- def coco_icon(icon_name = nil, **kwargs, &block)
16
- render Coco::Icon.new(name: icon_name, **kwargs), &block
15
+ def coco_icon(icon_name = nil, **, &block)
16
+ render Coco::Icon.new(name: icon_name, **), &block
17
17
  end
18
18
 
19
- def coco_embed(platform, url = nil, **kwargs)
19
+ def coco_embed(platform, url = nil, **)
20
20
  case platform
21
21
  when :youtube
22
- render Coco::Embeds::Youtube.new(url: url, **kwargs)
22
+ render Coco::Embeds::Youtube.new(url: url, **)
23
23
  else
24
24
  raise ArgumentError, "`#{platform}` is not a valid embed type"
25
25
  end
26
26
  end
27
27
 
28
- def coco_placeholder(*args, **kwargs, &block)
29
- render Coco::Placeholder.new(*args, **kwargs), &block
28
+ def coco_placeholder(*, **, &block)
29
+ render Coco::Placeholder.new(*, **), &block
30
+ end
31
+
32
+ def coco_modal(name = "default", **, &block)
33
+ render(Coco::Modal.new(name: name, **), &block)
34
+ end
35
+
36
+ def coco_modal_dialog(name = "default", **, &block)
37
+ render(Coco::Modal.new(name: name, **)) do |modal|
38
+ modal.with_dialog(&block)
39
+ end
40
+ end
41
+
42
+ def coco_modal_link(*, data: {}, modal: nil, **kwargs, &)
43
+ kwargs[:data] = coco_modal_data_attributes(modal || "default").merge(data)
44
+
45
+ link_to(*, **kwargs, &)
46
+ end
47
+
48
+ def coco_modal_frame_id(name = "default")
49
+ "coco-modal-frame-#{name.to_s.dasherize}"
50
+ end
51
+
52
+ def coco_modal_data_attributes(name = "default")
53
+ {
54
+ turbo: true,
55
+ turbo_frame: coco_modal_frame_id(name)
56
+ }
30
57
  end
31
58
  end
32
59
  end
data/lib/coco/engine.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "rails/engine"
2
2
  require "view_component"
3
+ require "turbo-rails"
3
4
 
4
5
  module Coco
5
6
  class Engine < ::Rails::Engine
data/lib/coco.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Coco
2
- VERSION = "0.6.5"
2
+ VERSION = "0.7.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coveragebook_components
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.5
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Perkins
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-08 00:00:00.000000000 Z
11
+ date: 2023-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '2.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: turbo-rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  description:
56
70
  email:
57
71
  - dev@coveragebook.com
@@ -1487,6 +1501,14 @@ files:
1487
1501
  - app/components/coco/base/image_uploader/image_uploader.rb
1488
1502
  - app/components/coco/base/link/link.css
1489
1503
  - app/components/coco/base/link/link.rb
1504
+ - app/components/coco/base/modal/modal.css
1505
+ - app/components/coco/base/modal/modal.html.erb
1506
+ - app/components/coco/base/modal/modal.js
1507
+ - app/components/coco/base/modal/modal.rb
1508
+ - app/components/coco/base/modal_dialog/modal_dialog.css
1509
+ - app/components/coco/base/modal_dialog/modal_dialog.html.erb
1510
+ - app/components/coco/base/modal_dialog/modal_dialog.js
1511
+ - app/components/coco/base/modal_dialog/modal_dialog.rb
1490
1512
  - app/components/coco/base/placeholder/placeholder.css
1491
1513
  - app/components/coco/base/placeholder/placeholder.html.erb
1492
1514
  - app/components/coco/base/placeholder/placeholder.rb