Skip to content

Commit

Permalink
[PBNTR-415] Adding Star Rating form controls (#3600)
Browse files Browse the repository at this point in the history
**What does this PR do?**
Adding Star Rating form controls

**How to test?** Steps to confirm the desired behavior:
1. Go to the Form kit page
2. Scroll down to the last input (Star Rating kit)

#### 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.
  • Loading branch information
carloslimasd authored Aug 23, 2024
1 parent 53b648c commit 4b051ec
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
<%= form.collection_select :example_collection_select, example_collection, :value, :name, props: { label: true, blank_selection: "Select One...", required: true } %>
<%= form.check_box :example_checkbox, props: { text: "Example Checkbox", label: true, required: true } %>
<%= form.date_picker :example_date_picker_2, props: { label: true, required: true } %>
<%= form.star_rating_field :example_star_rating, props: { variant: "interactive", label: true, required: true } %>

<%= form.actions do |action| %>
<%= action.submit %>
Expand Down
119 changes: 78 additions & 41 deletions playbook/app/pb_kits/playbook/pb_star_rating/index.js
Original file line number Diff line number Diff line change
@@ -1,119 +1,156 @@
import PbEnhancedElement from "../pb_enhanced_element";
import PbEnhancedElement from "../pb_enhanced_element"

const STAR_RATING_SELECTOR = "[data-pb-star-rating]";
const STAR_RATING_INPUT_ID = "star-rating-input";
const STAR_RATING_WRAPPER_SELECTOR = "[data-pb-star-rating-wrapper]"
const STAR_RATING_SELECTOR = "[data-pb-star-rating]"
const STAR_RATING_INPUT_DATA_SELECTOR = "[data-pb-star-rating-input]"

export default class PbStarRating extends PbEnhancedElement {
static get selector() {
return STAR_RATING_SELECTOR;
return STAR_RATING_WRAPPER_SELECTOR
}

connect() {
this.element.addEventListener("click", (event) => {
const clickedStarId = event.currentTarget.id;
this.updateStarColors(clickedStarId);
this.updateHiddenInputValue(clickedStarId);
});
this.addEventListeners()
this.handleFormReset()
}

addEventListeners() {
this.element.querySelectorAll(STAR_RATING_SELECTOR).forEach(star => {
star.addEventListener("click", (event) => {
const clickedStarId = event.currentTarget.id
this.updateStarColors(clickedStarId)
this.updateHiddenInputValue(clickedStarId)
this.clearFormValidation()
})

document.querySelectorAll(STAR_RATING_SELECTOR).forEach(star => {
star.addEventListener("mouseenter", (event) => {
const hoveredStarId = event.currentTarget.id
this.updateStarHoverColors(hoveredStarId);
this.updateStarHoverColors(hoveredStarId)
})

star.addEventListener("mouseleave", () => {
this.removeStarHoverColors();
this.removeStarHoverColors()
})

star.addEventListener("keydown", (event) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
this.handleStarClick(star.id);
event.preventDefault()
this.handleStarClick(star.id)
}
})
})
}

handleStarClick(starId) {
this.updateStarColors(starId);
this.updateHiddenInputValue(starId);
this.updateStarColors(starId)
this.updateHiddenInputValue(starId)
}

updateStarColors(clickedStarId) {
const allStars = document.querySelectorAll(STAR_RATING_SELECTOR);
const allStars = this.element.querySelectorAll(STAR_RATING_SELECTOR)

allStars.forEach(star => {
const starId = star.id;
const icon = star.querySelector(".interactive-star-icon");
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");
icon.classList.add("yellow-star-selected")
} else if (star.classList.contains("primary_star_light")) {
icon.classList.add("primary-star-selected");
icon.classList.add("primary-star-selected")
} else if (star.classList.contains("primary_star_dark")) {
icon.classList.add("primary-star-selected");
icon.classList.add("primary-star-selected")
} else if (star.classList.contains("subtle_star_light")) {
icon.classList.add("subtle-star-selected");
icon.classList.add("subtle-star-selected")
} else if (star.classList.contains("subtle_star_dark")) {
icon.classList.add("subtle-star-selected");
icon.classList.add("subtle-star-selected")
} else {
icon.classList.add("yellow-star-selected");
icon.classList.add("yellow-star-selected")
}
} else {
icon.classList.remove("yellow-star-selected", "primary-star-selected", "subtle-star-selected");
icon.classList.remove("yellow-star-selected", "primary-star-selected", "subtle-star-selected")
}
icon.classList.remove("star-hovered");
icon.classList.remove("star-hovered")
}
});
})
}

updateHiddenInputValue(value) {
const hiddenInput = document.getElementById(STAR_RATING_INPUT_ID);
const hiddenInput = this.element.querySelector(STAR_RATING_INPUT_DATA_SELECTOR)
if (hiddenInput) {
hiddenInput.value = value;
hiddenInput.value = value
}
}

updateStarHoverColors(hoveredStarId) {
const allStars = document.querySelectorAll(STAR_RATING_SELECTOR);
const allStars = this.element.querySelectorAll(STAR_RATING_SELECTOR)

allStars.forEach(star => {
const starId = star.id;
const icon = star.querySelector(".interactive-star-icon");
const starId = star.id
const icon = star.querySelector(".interactive-star-icon")

if (icon) {
if (starId <= hoveredStarId) {
if (!icon.classList.contains("yellow-star-selected") &&
!icon.classList.contains("primary-star-selected") &&
!icon.classList.contains("subtle-star-selected")) {
icon.classList.add("star-hovered");
icon.classList.add("star-hovered")
}
} else {
icon.classList.remove("star-hovered");
icon.classList.remove("star-hovered")
}
}
});
})
}


removeStarHoverColors() {
const allStars = document.querySelectorAll(STAR_RATING_SELECTOR);
const allStars = this.element.querySelectorAll(STAR_RATING_SELECTOR)

allStars.forEach(star => {
const icon = star.querySelector(".interactive-star-icon");
const icon = star.querySelector(".interactive-star-icon")
if (icon) {
if (!icon.classList.contains("yellow-star-selected") &&
!icon.classList.contains("primary-star-selected") &&
!icon.classList.contains("subtle-star-selected")) {
icon.classList.remove("star-hovered");
icon.classList.remove("star-hovered")
}
}
});
})
}

isStarSelected() {
return document.querySelectorAll(".yellow-star-selected, .primary-star-selected, .subtle-star-selected").length > 0;
return this.element.querySelectorAll(".yellow-star-selected, .primary-star-selected, .subtle-star-selected").length > 0
}

handleFormReset() {
const form = this.element.closest("form")
if (form) {
form.addEventListener("reset", () => {
this.updateHiddenInputValue("")
this.resetStarRatingValues()
})
}
}

resetStarRatingValues() {
const allStars = this.element.querySelectorAll(STAR_RATING_SELECTOR)
allStars.forEach(star => {
const icon = star.querySelector(".interactive-star-icon")
if (icon) {
icon.classList.remove("yellow-star-selected", "primary-star-selected", "subtle-star-selected")
}
})
}

clearFormValidation() {
const hiddenInput = this.element.querySelector(STAR_RATING_INPUT_DATA_SELECTOR)
if (hiddenInput.checkValidity()) {
const errorLabelElement = this.element.querySelector(".pb_body_kit_negative")
if (errorLabelElement) {
errorLabelElement.remove()
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,13 @@
<% end %>

<% else %>
<%= pb_rails("flex", props: { orientation: "column" }) do %>
<%= pb_rails("flex", props: { data: {"pb-star-rating-wrapper": "true" }, orientation: "column" }) do %>
<% if object.label.present? %>
<%= pb_rails("caption", props: {text: object.label, margin_bottom:"xs"}) %>
<% end %>
<input type="hidden" id="star-rating-input" value="" name="<%= object.name %>"/>

<%= hidden_input_tag %>

<%= pb_rails("flex", props: { orientation: "row" }) do %>
<% object.denominator.times do |index| %>
<div data-pb-star-rating id="<%= index + 1 %>" class="<%= star_color %>">
Expand Down
17 changes: 17 additions & 0 deletions playbook/app/pb_kits/playbook/pb_star_rating/star_rating.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ class StarRating < Playbook::KitBase
default: "display"
prop :label, type: Playbook::Props::String
prop :name, type: Playbook::Props::String
prop :required, type: Playbook::Props::Boolean,
default: false
prop :input_options, type: Playbook::Props::HashProp,
default: {}

def one_decimal_rating
rating.to_f.round(1)
Expand Down Expand Up @@ -106,6 +110,19 @@ def star_svg_path
def classname
generate_classname("pb_star_rating_kit")
end

def hidden_input_tag
tag(:input, all_input_options)
end

def all_input_options
input_options.merge(
data: { "pb-star-rating-input": true },
name: name,
required: required,
style: "display: none"
)
end
end
end
end

0 comments on commit 4b051ec

Please sign in to comment.