<rating-stars>
<fieldset>
<legend class="visually-hidden">Rate</legend>
<label data-key="1">
<input type="radio" class="visually-hidden" name="rating" value="1">
<span class="label">☆</span>
</label>
<label data-key="2">
<input type="radio" class="visually-hidden" name="rating" value="2">
<span class="label">☆</span>
</label>
<label data-key="3">
<input type="radio" class="visually-hidden" name="rating" value="3">
<span class="label">☆</span>
</label>
<label data-key="4">
<input type="radio" class="visually-hidden" name="rating" value="4">
<span class="label">☆</span>
</label>
<label data-key="5">
<input type="radio" class="visually-hidden" name="rating" value="5">
<span class="label">☆</span>
</label>
</fieldset>
</rating-stars>
rating-stars {
display: inline-block;
& fieldset {
display: flex;
border: none;
margin: 0;
padding: 0;
justify-content: center;
}
& label {
display: block;
cursor: pointer;
width: var(--input-height);
height: var(--input-height);
color: var(--color-primary);
font-size: var(--font-size-l);
border-radius: var(--space-xs);
text-align: center;
&:hover,
&:focus-within {
color: var(--color-primary-hover);
background-color: rgba(0, 0, 0, 0.05);
}
&:active {
color: var(--color-primary-active);
background-color: rgba(0, 0, 0, 0.1);
}
}
}
import {
type Component,
all,
asInteger,
component,
emit,
on,
setProperty,
setText,
} from "../../../";
export type RatingStarsProps = {
value: number;
};
export default component(
"rating-stars",
{
value: asInteger(),
},
(el) => {
const getKey = (element: HTMLElement): number =>
parseInt(element.dataset["key"] || "0");
return [
all<RatingStarsProps, HTMLInputElement>(
"input",
setProperty("checked", (target) => el.value === getKey(target)),
on("change", (e) => {
e.stopPropagation();
const value =
parseInt((e.currentTarget as HTMLInputElement)?.value) +
1;
el.value = value;
emit("change-rating", value)(el);
}),
),
all<RatingStarsProps, HTMLElement>(
".label",
setText((target) => (getKey(target) <= el.value ? "★" : "☆")),
),
];
},
);
declare global {
interface HTMLElementTagNameMap {
"rating-stars": Component<RatingStarsProps>;
}
}