coveragebook_components 0.6.5 → 0.7.0

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.
@@ -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