turbo_material 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +247 -0
  4. data/Rakefile +8 -0
  5. data/app/assets/config/turbo_material_manifest.js +3 -0
  6. data/app/assets/dist/turbo_material/tailwind.css +1 -0
  7. data/app/assets/javascripts/turbo_material/material_checkbox_controller.js +12 -0
  8. data/app/assets/javascripts/turbo_material/material_chips_input_controller.js +140 -0
  9. data/app/assets/javascripts/turbo_material/material_chips_select_controller.js +111 -0
  10. data/app/assets/javascripts/turbo_material/material_dialog_controller.js +27 -0
  11. data/app/assets/javascripts/turbo_material/material_input_controller.js +10 -0
  12. data/app/assets/javascripts/turbo_material/material_list_controller.js +57 -0
  13. data/app/assets/javascripts/turbo_material/material_menu_surface_controller.js +11 -0
  14. data/app/assets/javascripts/turbo_material/material_radio_controller.js +10 -0
  15. data/app/assets/javascripts/turbo_material/material_ripple_controller.js +10 -0
  16. data/app/assets/javascripts/turbo_material/material_select_controller.js +10 -0
  17. data/app/assets/javascripts/turbo_material/material_switch_controller.js +14 -0
  18. data/app/assets/stylesheets/turbo_material/application.css +15 -0
  19. data/app/assets/stylesheets/turbo_material/application.tailwind.css +3 -0
  20. data/app/controllers/turbo_material/application_controller.rb +4 -0
  21. data/app/helpers/turbo_material/application_helper.rb +7 -0
  22. data/app/helpers/turbo_material/checkbox_helper.rb +7 -0
  23. data/app/helpers/turbo_material/chips_input_helper.rb +7 -0
  24. data/app/helpers/turbo_material/chips_select_helper.rb +7 -0
  25. data/app/helpers/turbo_material/input_helper.rb +7 -0
  26. data/app/helpers/turbo_material/modal_helper.rb +7 -0
  27. data/app/helpers/turbo_material/radio_helper.rb +7 -0
  28. data/app/helpers/turbo_material/select_helper.rb +7 -0
  29. data/app/helpers/turbo_material/switch_helper.rb +7 -0
  30. data/app/helpers/turbo_material/textarea_helper.rb +7 -0
  31. data/app/jobs/turbo_material/application_job.rb +4 -0
  32. data/app/mailers/turbo_material/application_mailer.rb +6 -0
  33. data/app/models/turbo_material/application_record.rb +5 -0
  34. data/app/views/components/_checkbox.html.erb +25 -0
  35. data/app/views/components/_chips_input.html.erb +36 -0
  36. data/app/views/components/_chips_input_options.html.erb +20 -0
  37. data/app/views/components/_chips_select.html.erb +56 -0
  38. data/app/views/components/_input.html.erb +32 -0
  39. data/app/views/components/_modal.html.erb +37 -0
  40. data/app/views/components/_radio.html.erb +28 -0
  41. data/app/views/components/_select.html.erb +67 -0
  42. data/app/views/components/_switch.html.erb +34 -0
  43. data/app/views/components/_textarea.html.erb +30 -0
  44. data/app/views/layouts/turbo_material/application.html.erb +21 -0
  45. data/config/importmap.rb +4 -0
  46. data/config/routes.rb +2 -0
  47. data/config/tailwind.config.js +26 -0
  48. data/lib/tasks/turbo_material_tasks.rake +4 -0
  49. data/lib/turbo_material/engine.rb +44 -0
  50. data/lib/turbo_material/version.rb +3 -0
  51. data/lib/turbo_material.rb +6 -0
  52. metadata +164 -0
@@ -0,0 +1,27 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class extends Controller {
4
+ dialog = undefined;
5
+
6
+ static values = {
7
+ opened: Boolean
8
+ }
9
+
10
+ connect() {
11
+ this.dialog = mdc.dialog.MDCDialog.attachTo(this.element);
12
+ if (this.openedValue) {
13
+ this.dialog.open();
14
+ }
15
+ }
16
+
17
+ close() {
18
+ this.dialog.close();
19
+ }
20
+
21
+ open() {
22
+ this.dialog.open();
23
+ }
24
+
25
+ disconnect() {
26
+ }
27
+ }
@@ -0,0 +1,10 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class extends Controller {
4
+ connect() {
5
+ mdc.textField.MDCTextField.attachTo(this.element);
6
+ }
7
+
8
+ disconnect() {
9
+ }
10
+ }
@@ -0,0 +1,57 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class extends Controller {
4
+ connect() {
5
+ this.list = mdc.list.MDCList.attachTo(this.element);
6
+ this.list.listen('MDCList:action', (event) => {
7
+ this.focusElement(event.detail.index);
8
+ this.element.dispatchEvent(new CustomEvent('country-select-focus', {
9
+ bubbles: true,
10
+ cancelable: true,
11
+ detail: {
12
+ index: event.detail.index
13
+ }
14
+ }));
15
+ });
16
+ }
17
+
18
+ selected() {
19
+ return this.list.listElements[this.list.selectedIndex];
20
+ }
21
+
22
+ focusNext() {
23
+ if (this.list.selectedIndex === undefined ) {
24
+ this.list.selectedIndex = 0;
25
+ } else if (this.list.selectedIndex < this.list.listElements.length - 1) {
26
+ this.list.selectedIndex++;
27
+ } else {
28
+ this.list.selectedIndex = 0;
29
+ }
30
+ this.element.querySelector(".mdc-deprecated-list-item--selected").scrollIntoView({
31
+ behavior: 'smooth'
32
+ });
33
+ }
34
+
35
+ focusPrevious() {
36
+ if (this.list.selectedIndex === undefined ) {
37
+ this.list.selectedIndex = this.list.listElements.length - 1;
38
+ } else if (this.list.selectedIndex > 0) {
39
+ this.list.selectedIndex--;
40
+ } else {
41
+ this.list.selectedIndex = this.list.listElements.length - 1;
42
+ }
43
+ this.element.querySelector(".mdc-deprecated-list-item--selected").scrollIntoView({
44
+ behavior: 'smooth'
45
+ });
46
+ }
47
+
48
+ focusElement(index) {
49
+ this.list.selectedIndex = index;
50
+ this.element.querySelector(".mdc-deprecated-list-item--selected").scrollIntoView({
51
+ behavior: 'smooth'
52
+ });
53
+ }
54
+
55
+ disconnect() {
56
+ }
57
+ }
@@ -0,0 +1,11 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class extends Controller {
4
+
5
+ connect() {
6
+ this.menuSurface = new mdc.menuSurface.MDCMenuSurface.attachTo(this.element);
7
+ }
8
+
9
+ disconnect() {
10
+ }
11
+ }
@@ -0,0 +1,10 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class extends Controller {
4
+ connect() {
5
+ const select = mdc.radio.MDCRadio.attachTo(this.element);
6
+ }
7
+
8
+ disconnect() {
9
+ }
10
+ }
@@ -0,0 +1,10 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class extends Controller {
4
+ connect() {
5
+ mdc.ripple.MDCRipple.attachTo(this.element);
6
+ }
7
+
8
+ disconnect() {
9
+ }
10
+ }
@@ -0,0 +1,10 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class extends Controller {
4
+ connect() {
5
+ const select = mdc.select.MDCSelect.attachTo(this.element)
6
+ }
7
+
8
+ disconnect() {
9
+ }
10
+ }
@@ -0,0 +1,14 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class extends Controller {
4
+ connect() {
5
+ const switchControl = mdc.switchControl.MDCSwitch.attachTo(this.element.querySelector('.mdc-switch'));
6
+ const hidden = this.element.querySelector('input[type=hidden]');
7
+ switchControl.listen('click', () => {
8
+ hidden.value = switchControl.selected;
9
+ });
10
+ }
11
+
12
+ disconnect() {
13
+ }
14
+ }
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,3 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
@@ -0,0 +1,4 @@
1
+ module TurboMaterial
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,7 @@
1
+ module TurboMaterial
2
+ module ApplicationHelper
3
+ def cast_boolean(param)
4
+ ActiveRecord::Type::Boolean.new.cast(param)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module TurboMaterial
2
+ module CheckboxHelper
3
+ def material_checkbox(kwargs = {})
4
+ render "components/checkbox", **kwargs
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module TurboMaterial
2
+ module ChipsInputHelper
3
+ def material_chips_input(kwargs = {})
4
+ render "components/chips_input", **kwargs
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module TurboMaterial
2
+ module ChipsSelectHelper
3
+ def material_chips_select(kwargs = {})
4
+ render "components/chips_select", **kwargs
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module TurboMaterial
2
+ module InputHelper
3
+ def material_input(kwargs = {})
4
+ render "components/input", **kwargs
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module TurboMaterial
2
+ module ModalHelper
3
+ def material_modal(kwargs = {})
4
+ render "components/modal", **kwargs
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module TurboMaterial
2
+ module RadioHelper
3
+ def material_radio(kwargs = {})
4
+ render "components/radio", **kwargs
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module TurboMaterial
2
+ module SelectHelper
3
+ def material_select(kwargs = {})
4
+ render "components/select", **kwargs
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module TurboMaterial
2
+ module SwitchHelper
3
+ def material_switch(kwargs = {})
4
+ render "components/switch", **kwargs
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module TurboMaterial
2
+ module TextareaHelper
3
+ def material_textarea(kwargs = {})
4
+ render "components/textarea", **kwargs
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ module TurboMaterial
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module TurboMaterial
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: "from@example.com"
4
+ layout "mailer"
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module TurboMaterial
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,25 @@
1
+ <%# locals: (form:, disabled: false, name:, label: nil, id:, checked: false, checked_value: '1', unchecked_value: '0', frame: nil, source_override: nil) %>
2
+ <div class="mdc-form-field" data-controller="material-checkbox">
3
+ <div class="mdc-checkbox <%= disabled ? 'mdc-checkbox--disabled' : '' %>">
4
+ <%= form.check_box name.to_sym, {
5
+ id: id, class: "mdc-checkbox__native-control",
6
+ disabled: disabled,
7
+ checked: checked || form&.object&.[](source_override || name.to_sym),
8
+ data: { frame: frame }.compact
9
+ }, checked_value, unchecked_value %>
10
+ <div class="mdc-checkbox__background">
11
+ <svg class="mdc-checkbox__checkmark"
12
+ viewBox="0 0 24 24">
13
+ <path class="mdc-checkbox__checkmark-path"
14
+ fill="none"
15
+ d="M1.73,12.91 8.1,19.28 22.79,4.59"/>
16
+ </svg>
17
+ <div class="mdc-checkbox__mixedmark"></div>
18
+ </div>
19
+ <div class="mdc-checkbox__ripple"></div>
20
+ <div class="mdc-checkbox__focus-ring"></div>
21
+ </div>
22
+ <label for="<%= id %>">
23
+ <%= label || name.capitalize %>
24
+ </label>
25
+ </div>
@@ -0,0 +1,36 @@
1
+ <%# locals: (form:, disabled: false, required: false, name:, label: nil, id:, frame: nil, suffix: nil, type: 'text', url: nil, selected: [], options: [], value: nil) %>
2
+ <%- id = [name, suffix].compact_blank.join('-') -%>
3
+ <div data-controller="material-chips-input"
4
+ data-material-chips-input-url-value="<%= url %>"
5
+ data-material-chips-input-name-value="<%= name %>"
6
+ data-material-chips-input-material-list-outlet="#<%= "#{id}-list" %>"
7
+ <% if suffix.present? %>data-material-chips-input-suffix-value="<%= suffix %>"<% end %>
8
+ data-action="keydown.esc->material-chips-input#close keydown.enter->prevent-default country-select-focus->material-chips-input#confirmSelection"
9
+ >
10
+ <label class="mdc-text-field mdc-text-field--filled w-full !h-max !h-full">
11
+ <span class="mdc-text-field__ripple"></span>
12
+ <span class="mdc-floating-label !top-6"><%= label %></span>
13
+ <div class="mdc-chip-set mdc-chip-set--input !pt-8 w-full" role="grid">
14
+ <%- selected.each do |chip| -%>
15
+ <div class="mdc-chip">
16
+ <div class="mdc-chip__text"><%= chip[:label] %></div>
17
+ <!-- <i class="material-icons mdc-chip__icon mdc-chip__icon--trailing" tabindex="0" role="button">cancel</i>-->
18
+ </div>
19
+ <%- end -%>
20
+ <%= form.hidden_field name.to_sym, value: value, data: { 'material-chips-input-target': 'hidden' } %>
21
+ <%= form.text_field "#{name}_".to_sym,
22
+ class: 'mdc-text-field__input', value: value || form&.object&.[](name.to_sym),
23
+ id: id, 'aria-labelledby' => id + '-label',
24
+ required: required,
25
+ disabled: disabled,
26
+ type: type, autocomplete: "off",
27
+ data: { 'material-chips-input-target': 'input',
28
+ action: 'input->material-chips-input#search mousedown->material-chips-input#toggle keydown.down->material-chips-input#focusNext keydown.up->material-chips-input#focusPrevious keydown.enter->material-chips-input#confirmSelection keydown->material-chips-input#open' }
29
+ %>
30
+ </div>
31
+ <span class="mdc-line-ripple"></span>
32
+ </label>
33
+ <div class="mdc-menu-surface--anchor">
34
+ <%= render partial: 'components/chips_input_options', locals: { options: options, suffix: suffix, name: name, label: label } %>
35
+ </div>
36
+ </div>
@@ -0,0 +1,20 @@
1
+ <%# locals: (suffix:, options: [], label:, name:, opened: 'false') %>
2
+ <%- id = [name, suffix].compact_blank.join('-') -%>
3
+ <div id="<%= "#{id}-panel" %>"
4
+ class="mdc-menu-surface <%= (opened != 'true' || options.size.zero?) ? '' : 'mdc-menu-surface--open' %> !z-100 mdc-menu-surface--fullwidth"
5
+ data-controller="material-menu-surface"
6
+ data-material-chips-input-target="panel" data-size="<%= options.size %>">
7
+ <ul class="mdc-deprecated-list max-h-64 overflow-y-auto"
8
+ id="<%= "#{id}-list" %>"
9
+ role="listbox"
10
+ aria-label="<%= label %>"
11
+ data-controller="material-list"
12
+ >
13
+ <%- options.each_with_index do |option, idx| -%>
14
+ <li class="mdc-deprecated-list-item" data-value="<%= option[:id] %>" data-name="<%= option[:label] %>" <% if idx.zero? %> tabindex="0"<% end %>>
15
+ <span class="mdc-deprecated-list-item__ripple"></span>
16
+ <span class="mdc-deprecated-list-item__text"><%= option[:label] %></span>
17
+ </li>
18
+ <%- end -%>
19
+ </ul>
20
+ </div>
@@ -0,0 +1,56 @@
1
+ <%# locals: (form:, disabled: false, required: false, name:, label: nil, id:, value: nil, url: nil, frame: nil, source_override: nil, options: [], confirmable: false, query_string: nil, modal_name: nil, modal_url: nil, chip_css: nil, fixed: false) %>
2
+ <div class="mdc-select mdc-select--filled w-full"
3
+ data-controller="material-chips-select"
4
+ data-material-chips-select-selected-value="<%= value %>"
5
+ data-material-chips-select-url-value="<%= url %>"
6
+ data-material-chips-select-confirmable-value="<%= confirmable %>"
7
+ data-material-chips-select-query-string-value="<%= query_string %>"
8
+ data-material-chips-select-modal-name-value="<%= modal_name %>"
9
+ data-material-chips-select-modal-url-value="<%= modal_url %>"
10
+ data-material-chips-select-chip-css-value="<%= chip_css %>"
11
+ >
12
+ <div class="mdc-select__anchor"
13
+ role="button"
14
+ aria-haspopup="listbox"
15
+ aria-expanded="false"
16
+ aria-expanded="false"
17
+ aria-labelledby="<%= id %>-label <%= id %>-selected-text"
18
+ <% if disabled %>aria-disabled="true"<% end %>
19
+ <% if required %>aria-required="true"<% end %>
20
+ >
21
+ <span class="mdc-select__ripple"></span>
22
+ <span id="<%= id %>-label" class="mdc-floating-label pb-1"><%= label || name.capitalize %></span>
23
+ <div class="mdc-chip-set mdc-chip-set--input"></div>
24
+ <span class="mdc-select__selected-text-container"><span id="<%= id %>-selected-text" class="mdc-select__selected-text !hidden"></span></span>
25
+ <span class="mdc-select__dropdown-icon">
26
+ <svg
27
+ class="mdc-select__dropdown-icon-graphic"
28
+ viewBox="7 10 10 5" focusable="false">
29
+ <polygon
30
+ class="mdc-select__dropdown-icon-inactive"
31
+ stroke="none"
32
+ fill-rule="evenodd"
33
+ points="7 10 12 15 17 10">
34
+ </polygon>
35
+ <polygon
36
+ class="mdc-select__dropdown-icon-active"
37
+ stroke="none"
38
+ fill-rule="evenodd"
39
+ points="7 15 12 10 17 15">
40
+ </polygon>
41
+ </svg>
42
+ </span>
43
+ <span class="mdc-line-ripple"></span>
44
+ </div>
45
+ <%= form.hidden_field name.to_sym, value: value, data: { 'material-chips-select-target': 'hidden' } if form %>
46
+ <div class="mdc-select__menu mdc-menu mdc-menu-surface <%= fixed ? 'mdc-menu-surface--fixed' : 'mdc-menu-surface--fullwidth' %>">
47
+ <ul class="mdc-deprecated-list" role="listbox" aria-label="<%= label %> listbox">
48
+ <% options.each do |option| %>
49
+ <li class="mdc-deprecated-list-item" aria-selected="false" data-value="<%= option[:value] %>" data-label="<%= option[:label] %>" <% if option[:confirmed].in? [true, false] %>data-confirmed="<%= option[:confirmed] %>"<% end %> role="option">
50
+ <span class="mdc-deprecated-list-item__ripple"></span>
51
+ <span class="mdc-deprecated-list-item__text"><%= option[:label] %></span>
52
+ </li>
53
+ <% end %>
54
+ </ul>
55
+ </div>
56
+ </div>
@@ -0,0 +1,32 @@
1
+ <%# locals: (form:, custom_controller: nil, custom_css: nil, disabled: false, required: false, name:, label: nil, id:, checked: false, frame: nil, provide_hidden: false, value: nil, type: 'text', data: {}, min: nil, max: nil, helper: nil, parent: nil) %>
2
+ <label class="mdc-text-field mdc-text-field--filled w-full <%= custom_css %>"
3
+ data-controller="<%= custom_controller || 'material-input' %>" <% if frame %>data-frame="<%= frame %>"<% end %>>
4
+ <span class="mdc-text-field__ripple"></span>
5
+ <span class="mdc-floating-label" id="<%= id %>-label">
6
+ <%= label || name.capitalize %>
7
+ </span>
8
+ <%= form.text_field provide_hidden ? "#{name}_".to_sym : name.to_sym,
9
+ class: 'mdc-text-field__input', value: value || form&.object&.[](name.to_sym),
10
+ id: id, 'aria-labelledby' => id + '-label',
11
+ required: required, disabled: disabled,
12
+ type: type, autocomplete: "off", data: { frame: frame, **(data) }.compact,
13
+ min: min, max: max
14
+ %>
15
+ <span class="mdc-line-ripple"></span>
16
+ <%- if provide_hidden -%>
17
+ <%= form.hidden_field name.to_sym, value: value, data: { frame: frame }.compact %>
18
+ <%- end -%>
19
+ </label>
20
+ <div class="mdc-text-field-helper-line">
21
+ <%- if helper -%>
22
+ <div class="mdc-text-field-helper-text" aria-hidden="true"><%= helper %></div>
23
+ <%- end -%>
24
+ <div class="mdc-text-field-helper-text--validation-msg text-sm text-red-500 hidden jserror">
25
+ </div>
26
+ <%- parent&.errors&.[](name.to_sym)&.each do |msg| -%>
27
+ <div class="mdc-text-field-helper-text--validation-msg text-sm text-red-500"
28
+ aria-hidden="true">
29
+ <%= msg %>
30
+ </div>
31
+ <%- end -%>
32
+ </div>
@@ -0,0 +1,37 @@
1
+ <%# locals: (title:) %>
2
+ <turbo-frame id="modal">
3
+ <div class="mdc-dialog" data-controller="material-dialog" data-material-dialog-opened-value="true">
4
+ <div class="mdc-dialog__container">
5
+ <div class="mdc-dialog__surface !min-w-[36rem] !min-h-[14rem]"
6
+ role="alertdialog"
7
+ aria-modal="true"
8
+ aria-labelledby="my-dialog-title"
9
+ aria-describedby="my-dialog-content">
10
+ <h2 class="mdc-dialog__title">
11
+ <div class="flex items-center justify-between">
12
+ <span><%= title %></span>
13
+ <button type="button" class="mdc-icon-button mdc-dialog__close" data-mdc-ripple-is-unbounded data-action="click->material-dialog#close">
14
+ <div class="mdc-icon-button__ripple"></div>
15
+ <span class="mdc-icon-button__focus-ring"></span>
16
+ <i class="material-icons !text-white">close</i>
17
+ </button>
18
+ </div>
19
+ </h2>
20
+ <div class="mdc-dialog__content">
21
+ Contents
22
+ </div>
23
+ <div class="mdc-dialog__actions">
24
+ <button type="button" class="mdc-button mdc-dialog__button mdc-dialog__close" data-action="click->material-dialog#close">
25
+ <div class="mdc-button__ripple"></div>
26
+ <span class="mdc-button__label">Cancel</span>
27
+ </button>
28
+ <button type="button" class="mdc-button mdc-dialog__button" data-controller="material-ripple">
29
+ <div class="mdc-button__ripple"></div>
30
+ <span class="mdc-button__label">OK</span>
31
+ </button>
32
+ </div>
33
+ </div>
34
+ </div>
35
+ <div class="mdc-dialog__scrim"></div>
36
+ </div>
37
+ </turbo-frame>
@@ -0,0 +1,28 @@
1
+ <%# locals: (form:, disabled: false, required: false, name:, label: nil, id:, checked: false, value: nil, parent: nil) %>
2
+ <div class="mdc-form-field flex flex-col">
3
+ <label>
4
+ <%= label || name.capitalize %>
5
+ </label>
6
+ <div class="flex flex-row items-center w-full">
7
+ <div class="mdc-radio <%= disabled ? 'mdc-radio--disabled' : '' %>" data-controller="material-radio">
8
+ <%= form.radio_button name.to_sym, 'true', class: 'mdc-radio__native-control', id: id + '-1', checked: value, disabled: disabled %>
9
+ <div class="mdc-radio__background">
10
+ <div class="mdc-radio__outer-circle"></div>
11
+ <div class="mdc-radio__inner-circle"></div>
12
+ </div>
13
+ <div class="mdc-radio__ripple"></div>
14
+ <div class="mdc-radio__focus-ring"></div>
15
+ </div>
16
+ <label for="<%= id %>-1">Yes</label>
17
+ <div class="mdc-radio <%= disabled ? 'mdc-radio--disabled' : '' %>">
18
+ <%= form.radio_button name.to_sym, 'false', class: 'mdc-radio__native-control', id: id + '-2', checked: !value, disabled: disabled %>
19
+ <div class="mdc-radio__background">
20
+ <div class="mdc-radio__outer-circle"></div>
21
+ <div class="mdc-radio__inner-circle"></div>
22
+ </div>
23
+ <div class="mdc-radio__ripple"></div>
24
+ <div class="mdc-radio__focus-ring"></div>
25
+ </div>
26
+ <label for="<%= id %>-2">No</label>
27
+ </div>
28
+ </div>
@@ -0,0 +1,67 @@
1
+ <%# locals: (form:, disabled: false, required: false, name:, label: nil, id:, checked: false, value: nil, parent: nil, frame: nil, selected_text: nil, fixed: false, options: [], hint: nil, helper: nil) %>
2
+ <div class="mdc-select mdc-select--filled w-full<%= disabled ? ' mdc-select--disabled' : '' %><%= required ? ' mdc-select--required' : '' %>"
3
+ data-controller="material-select" <% if frame %> data-frame="<%= frame %>"<% end %> id="<%= id %>">
4
+ <%= form.hidden_field name.to_sym, value: value %>
5
+ <div class="mdc-select__anchor"
6
+ role="button"
7
+ aria-haspopup="listbox"
8
+ aria-expanded="false"
9
+ aria-labelledby="<%= id %>-label <%= id %>-selected-text"
10
+ <% if disabled %>aria-disabled="true"<% end %>
11
+ <% if required %>aria-required="true"<% end %>
12
+ >
13
+ <span class="mdc-select__ripple"></span>
14
+ <span id="<%= id %>-label" class="mdc-floating-label"><%= label || name.capitalize %></span>
15
+ <span class="mdc-select__selected-text-container">
16
+ <span id="<%= id %>-selected-text" class="mdc-select__selected-text">
17
+ <%= selected_text || value %>
18
+ </span>
19
+ </span>
20
+ <span class="mdc-select__dropdown-icon">
21
+ <svg
22
+ class="mdc-select__dropdown-icon-graphic"
23
+ viewBox="7 10 10 5" focusable="false">
24
+ <polygon
25
+ class="mdc-select__dropdown-icon-inactive"
26
+ stroke="none"
27
+ fill-rule="evenodd"
28
+ points="7 10 12 15 17 10">
29
+ </polygon>
30
+ <polygon
31
+ class="mdc-select__dropdown-icon-active"
32
+ stroke="none"
33
+ fill-rule="evenodd"
34
+ points="7 15 12 10 17 15">
35
+ </polygon>
36
+ </svg>
37
+ </span>
38
+ <span class="mdc-line-ripple"></span>
39
+ </div>
40
+
41
+ <div class="mdc-select__menu mdc-menu mdc-menu-surface !z-100 <%= fixed ? 'mdc-menu-surface--fixed' : 'mdc-menu-surface--fullwidth' %>" id="<%= id %>-surface">
42
+ <ul class="mdc-deprecated-list" role="listbox" aria-label="<%= label %> listbox">
43
+ <% options.each do |option| %>
44
+ <li class="mdc-deprecated-list-item<%= value == option[:value] ? ' mdc-deprecated-list-item--selected' : '' %>" aria-selected="<%= (value == option[:value]).to_s %>" data-value="<%= option[:value] %>" role="option">
45
+ <span class="mdc-deprecated-list-item__ripple"></span>
46
+ <span class="mdc-deprecated-list-item__text"><%= option[:label] %></span>
47
+ </li>
48
+ <% end %>
49
+ </ul>
50
+ </div>
51
+ </div>
52
+ <%- if hint.present? -%>
53
+ <div class="font-sans text-xs p-2"><%= hint %></div>
54
+ <%- end -%>
55
+ <%- if helper.present? || parent&.errors.present? -%>
56
+ <div class="mdc-text-field-helper-line">
57
+ <%- if helper -%>
58
+ <div class="mdc-text-field-helper-text" aria-hidden="true"><%= helper %></div>
59
+ <%- end -%>
60
+ <%- parent&.errors&.[](name.to_sym)&.each do |msg| -%>
61
+ <div class="mdc-text-field-helper-text--validation-msg text-sm text-red-500"
62
+ aria-hidden="true">
63
+ <%= msg %>
64
+ </div>
65
+ <%- end -%>
66
+ </div>
67
+ <%- end -%>
@@ -0,0 +1,34 @@
1
+ <%# locals: (form:, disabled: false, name:, label: nil, id:, value: nil, true_label: nil, false_label: nil, frame: nil) %>
2
+ <div data-controller="material-switch" <% if frame %> data-frame="<%= frame %>"<% end %>>
3
+ <button id="selected-switch" class="mdc-switch <%= cast_boolean(value) ? 'mdc-switch--selected' : '' %>"
4
+ type="button" role="switch" aria-checked="<%= cast_boolean(value) ? 'true' : 'false' %>" <% if disabled %>disabled<% end %>>
5
+ <div class="mdc-switch__track"></div>
6
+ <div class="mdc-switch__handle-track">
7
+ <div class="mdc-switch__handle">
8
+ <div class="mdc-switch__shadow">
9
+ <div class="mdc-elevation-overlay"></div>
10
+ </div>
11
+ <div class="mdc-switch__ripple"></div>
12
+ <div class="mdc-switch__icons">
13
+ <svg class="mdc-switch__icon mdc-switch__icon--on" viewBox="0 0 24 24">
14
+ <path d="M19.69,5.23L8.96,15.96l-4.23-4.23L2.96,13.5l6,6L21.46,7L19.69,5.23z"/>
15
+ </svg>
16
+ <svg class="mdc-switch__icon mdc-switch__icon--off" viewBox="0 0 24 24">
17
+ <path d="M20 13H4v-2h16v2z"/>
18
+ </svg>
19
+ </div>
20
+ </div>
21
+ </div>
22
+ <span class="mdc-switch__focus-ring-wrapper">
23
+ <div class="mdc-switch__focus-ring"></div>
24
+ </span>
25
+ </button>
26
+ <label for="selected-switch">
27
+ <% if cast_boolean(value) %>
28
+ <%= true_label || label %>
29
+ <% else %>
30
+ <%= false_label || label %>
31
+ <% end %>
32
+ </label>
33
+ <%= form.hidden_field name.to_sym, value: value %>
34
+ </div>