From a07c7f8b22e650682e20619e4e17f19fdf8dd46d Mon Sep 17 00:00:00 2001 From: Nick Amantia <92755007+nickamantia@users.noreply.github.com> Date: Fri, 19 Jul 2024 09:28:20 -0400 Subject: [PATCH] [PBNTR-285] Star Rating kit: interactive form variant (Rails) (#3523) [PBNTR-285 ](https://runway.powerhrg.com/backlog_items/PBNTR-285) This PR adds a new interactive variant for the star rating kit. ![Screenshot 2024-07-11 at 4 13 27 PM](https://github.com/user-attachments/assets/3a708fa9-a697-454b-ab7e-22e5b7d8f30b) ![Screenshot 2024-07-11 at 4 13 46 PM](https://github.com/user-attachments/assets/0799b777-859e-46aa-a8c2-08315ef1cb16) **How to test?** Steps to confirm the desired behavior: 1. Go to the star rating kit 2. click to see the interactive functionally #### Checklist: - [x] **LABELS** Add a label: `enhancement`, `bug`, `improvement`, `new kit`, `deprecated`, or `breaking`. See [Changelog & Labels](https://github.com/powerhome/playbook/wiki/Changelog-&-Labels) for details. - [x] **DEPLOY** I have added the `milano` label to show I'm ready for a review. - [ ] **TESTS** I have added test coverage to my code. --- .../playbook/pb_star_rating/_star_rating.scss | 13 ++++- .../docs/_star_rating_interactive.html.erb | 1 + .../playbook/pb_star_rating/docs/example.yml | 2 +- .../pb_kits/playbook/pb_star_rating/index.js | 50 +++++++++++++++++++ .../pb_star_rating/star_rating.html.erb | 30 +++++++++-- .../playbook/pb_star_rating/star_rating.rb | 6 +++ .../app/pb_kits/playbook/playbook-rails.js | 3 ++ playbook/lib/playbook/forms/builder.rb | 1 + .../forms/builder/star_rating_field.rb | 14 ++++++ .../pb_kits/playbook/kits/star_rating_spec.rb | 6 +++ 10 files changed, 118 insertions(+), 8 deletions(-) create mode 100644 playbook/app/pb_kits/playbook/pb_star_rating/docs/_star_rating_interactive.html.erb create mode 100644 playbook/app/pb_kits/playbook/pb_star_rating/index.js create mode 100644 playbook/lib/playbook/forms/builder/star_rating_field.rb diff --git a/playbook/app/pb_kits/playbook/pb_star_rating/_star_rating.scss b/playbook/app/pb_kits/playbook/pb_star_rating/_star_rating.scss index f40cd68086..0965960c72 100644 --- a/playbook/app/pb_kits/playbook/pb_star_rating/_star_rating.scss +++ b/playbook/app/pb_kits/playbook/pb_star_rating/_star_rating.scss @@ -48,8 +48,8 @@ $star-styles: ( - yellow_star: (color: #F9BB00), - primary_star: (color: #0056CF), + yellow_star: (color: $yellow), + primary_star: (color: $royal), suble_star_light: (color: $text_lt_default), suble_star_dark: (color: $text_dk_default), empty_star_dark: (color: $border_dark), @@ -111,4 +111,13 @@ } } } + .yellow-star-selected { + color: $yellow; + } + .primary-star-selected { + color: $royal + } + .suble-star-selected { + color: $text_lt_default; + } } diff --git a/playbook/app/pb_kits/playbook/pb_star_rating/docs/_star_rating_interactive.html.erb b/playbook/app/pb_kits/playbook/pb_star_rating/docs/_star_rating_interactive.html.erb new file mode 100644 index 0000000000..41b1f249b1 --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_star_rating/docs/_star_rating_interactive.html.erb @@ -0,0 +1 @@ +<%= pb_rails("star_rating", props: { padding_bottom: "xs", variant: "interactive" }) %> \ No newline at end of file diff --git a/playbook/app/pb_kits/playbook/pb_star_rating/docs/example.yml b/playbook/app/pb_kits/playbook/pb_star_rating/docs/example.yml index d367d24b39..9253d7b9c7 100644 --- a/playbook/app/pb_kits/playbook/pb_star_rating/docs/example.yml +++ b/playbook/app/pb_kits/playbook/pb_star_rating/docs/example.yml @@ -13,4 +13,4 @@ examples: - star_rating_background_options: Background Options - star_rating_hide: Layout Options - star_rating_number_config: Number Config - - star_rating_size_options: Size Options + - star_rating_size_options: Size Options \ No newline at end of file diff --git a/playbook/app/pb_kits/playbook/pb_star_rating/index.js b/playbook/app/pb_kits/playbook/pb_star_rating/index.js new file mode 100644 index 0000000000..34b8eb3859 --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_star_rating/index.js @@ -0,0 +1,50 @@ +import PbEnhancedElement from "../pb_enhanced_element"; + +const STAR_RATING_SELECTOR = "[data-pb-star-rating]"; +const STAR_RATING_INPUT_ID = "star-rating-input"; + +export default class PbStarRating extends PbEnhancedElement { + static get selector() { + return STAR_RATING_SELECTOR; + } + + connect() { + this.element.addEventListener("click", (event) => { + const clickedStarId = event.currentTarget.id; + this.updateStarColors(clickedStarId); + this.updateHiddenInputValue(clickedStarId); + }); + } + + updateStarColors(clickedStarId) { + const allStars = document.querySelectorAll(STAR_RATING_SELECTOR); + + allStars.forEach(star => { + const starId = star.id; + const icon = star.querySelector(".interactive-star-icon"); + + if (icon) { + if (starId <= clickedStarId) { + if (star.classList.contains("yellow_star")) { + icon.classList.add("yellow-star-selected"); + } else if (star.classList.contains("primary_star")) { + icon.classList.add("primary-star-selected"); + } else if (star.classList.contains("suble_star_light")) { + icon.classList.add("suble-star-selected"); + } else { + icon.classList.add("yellow-star-selected"); + } + } else { + icon.classList.remove("yellow-star-selected", "primary-star-selected", "suble-star-selected"); + } + } + }); + } + + updateHiddenInputValue(value) { + const hiddenInput = document.getElementById(STAR_RATING_INPUT_ID); + if (hiddenInput) { + hiddenInput.value = value; + } + } +} diff --git a/playbook/app/pb_kits/playbook/pb_star_rating/star_rating.html.erb b/playbook/app/pb_kits/playbook/pb_star_rating/star_rating.html.erb index 21703f56ba..25814366d3 100644 --- a/playbook/app/pb_kits/playbook/pb_star_rating/star_rating.html.erb +++ b/playbook/app/pb_kits/playbook/pb_star_rating/star_rating.html.erb @@ -28,13 +28,33 @@ <% end %> <% end %> <%= pb_rails("flex", props: { }) do %> - <% object.star_count.times do %> - <%= pb_rails("icon", props: { classname: "#{star_color} pb_star_#{size}" , custom_icon: Playbook::Engine.root.join(star_svg_path) } ) %> - <% end %> - <% object.empty_stars.times do %> - <%= pb_rails("icon", props: { classname: "#{background_star_color} pb_star_#{size}", custom_icon: Playbook::Engine.root.join(background_star_path) } ) %> + + <% if object.variant == "display" %> + + <% object.star_count.times do %> + <%= pb_rails("icon", props: { classname: "#{star_color} pb_star_#{size}" , custom_icon: Playbook::Engine.root.join(star_svg_path) } ) %> + <% end %> + <% object.empty_stars.times do %> + <%= pb_rails("icon", props: { classname: "#{background_star_color} pb_star_#{size}", custom_icon: Playbook::Engine.root.join(background_star_path) } ) %> + <% end %> + + <% else %> + <%= pb_rails("flex", props: { orientation: "column" }) do %> + <% if object.label.present? %> + <%= pb_rails("caption", props: {text: object.label, margin_bottom:"xs"}) %> + <% end %> + + <%= pb_rails("flex", props: { orientation: "row" }) do %> + <% object.denominator.times do |index| %> +
+ <%= pb_rails("icon", props: { classname: "#{background_star_color} pb_star_#{size} interactive-star-icon", custom_icon: Playbook::Engine.root.join(background_star_path)} ) %> +
+ <% end %> + <% end %> + <% end %> <% end %> <% end %> + <% if layout_option == "onestar" %> <%= content_tag(:div, class: "pb_star_rating_number_#{size}") do %> <% case object.size %> diff --git a/playbook/app/pb_kits/playbook/pb_star_rating/star_rating.rb b/playbook/app/pb_kits/playbook/pb_star_rating/star_rating.rb index a6320b5400..d1c8536a5f 100644 --- a/playbook/app/pb_kits/playbook/pb_star_rating/star_rating.rb +++ b/playbook/app/pb_kits/playbook/pb_star_rating/star_rating.rb @@ -25,6 +25,12 @@ class StarRating < Playbook::KitBase values: %w[fill outline], default: "fill" + prop :variant, type: Playbook::Props::Enum, + values: %w[display interactive], + default: "display" + prop :label, type: Playbook::Props::String + prop :name, type: Playbook::Props::String + def one_decimal_rating rating.to_f.round(1) end diff --git a/playbook/app/pb_kits/playbook/playbook-rails.js b/playbook/app/pb_kits/playbook/playbook-rails.js index a8edc7b2b6..6a58f1c263 100644 --- a/playbook/app/pb_kits/playbook/playbook-rails.js +++ b/playbook/app/pb_kits/playbook/playbook-rails.js @@ -39,6 +39,9 @@ PbDropdown.start() import PbAdvancedTable from './pb_advanced_table' PbAdvancedTable.start() +import PbStarRating from './pb_star_rating' +PbStarRating.start() + import 'flatpickr' // React-Rendered Rails Kits ===== diff --git a/playbook/lib/playbook/forms/builder.rb b/playbook/lib/playbook/forms/builder.rb index 0fe0f9b3df..171d4ca34c 100644 --- a/playbook/lib/playbook/forms/builder.rb +++ b/playbook/lib/playbook/forms/builder.rb @@ -14,6 +14,7 @@ class Builder < ::ActionView::Helpers::FormBuilder require_relative "builder/multi_level_select_field" require_relative "builder/phone_number_field" require_relative "builder/dropdown_field" + require_relative "builder/star_rating_field" prepend(FormFieldBuilder.new(:email_field, kit_name: "text_input")) prepend(FormFieldBuilder.new(:number_field, kit_name: "text_input")) diff --git a/playbook/lib/playbook/forms/builder/star_rating_field.rb b/playbook/lib/playbook/forms/builder/star_rating_field.rb new file mode 100644 index 0000000000..3c3c266cbe --- /dev/null +++ b/playbook/lib/playbook/forms/builder/star_rating_field.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Playbook + module Forms + class Builder + def star_rating_field(name, props: {}) + props[:name] = name + props[:margin_bottom] = "sm" + props[:label] = @template.label(@object_name, name) if props[:label] == true + @template.pb_rails("star_rating", props: props) + end + end + end +end diff --git a/playbook/spec/pb_kits/playbook/kits/star_rating_spec.rb b/playbook/spec/pb_kits/playbook/kits/star_rating_spec.rb index e8f292c1ab..8cc8d43625 100644 --- a/playbook/spec/pb_kits/playbook/kits/star_rating_spec.rb +++ b/playbook/spec/pb_kits/playbook/kits/star_rating_spec.rb @@ -39,6 +39,12 @@ .with_values("xs", "sm", "md", "lg") } + it { + is_expected.to define_enum_prop(:variant) + .with_default("display") + .with_values("display", "interactive") + } + describe "#classname" do it "returns namespaced class name", :aggregate_failures do expect(subject.new({}).classname).to eq "pb_star_rating_kit"