@zag-js/rating-group
Version:
Core logic for the rating-group widget implemented as a state machine
226 lines (224 loc) • 8.12 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/rating-group.connect.ts
var rating_group_connect_exports = {};
__export(rating_group_connect_exports, {
connect: () => connect
});
module.exports = __toCommonJS(rating_group_connect_exports);
var import_dom_query = require("@zag-js/dom-query");
var dom = __toESM(require("./rating-group.dom.js"));
var import_rating_group = require("./rating-group.anatomy.js");
function connect(service, normalize) {
const { context, send, prop, scope, computed } = service;
const interactive = computed("isInteractive");
const disabled = computed("isDisabled");
const readOnly = !!prop("readOnly");
const required = !!prop("required");
const value = context.get("value");
const hoveredValue = context.get("hoveredValue");
const translations = prop("translations");
function getItemState(props) {
const currentValue = computed("isHovering") ? hoveredValue : value;
const equal = Math.ceil(currentValue) === props.index;
const highlighted = props.index <= currentValue || equal;
const half = equal && Math.abs(currentValue - props.index) === 0.5;
return {
highlighted,
half,
checked: equal || value <= 0 && props.index === 1
};
}
return {
hovering: computed("isHovering"),
value,
hoveredValue,
count: prop("count"),
items: Array.from({ length: prop("count") }).map((_, index) => index + 1),
setValue(value2) {
send({ type: "SET_VALUE", value: value2 });
},
clearValue() {
send({ type: "CLEAR_VALUE" });
},
getRootProps() {
return normalize.element({
...import_rating_group.parts.root.attrs,
dir: prop("dir"),
id: dom.getRootId(scope)
});
},
getHiddenInputProps() {
return normalize.input({
name: prop("name"),
form: prop("form"),
type: "text",
hidden: true,
disabled,
readOnly,
required: prop("required"),
id: dom.getHiddenInputId(scope),
defaultValue: value
});
},
getLabelProps() {
return normalize.label({
...import_rating_group.parts.label.attrs,
dir: prop("dir"),
id: dom.getLabelId(scope),
"data-disabled": (0, import_dom_query.dataAttr)(disabled),
"data-required": (0, import_dom_query.dataAttr)(required),
htmlFor: dom.getHiddenInputId(scope),
onClick(event) {
if (event.defaultPrevented) return;
if (!interactive) return;
event.preventDefault();
const radioEl = dom.getRadioEl(scope, Math.max(1, context.get("value")));
radioEl?.focus({ preventScroll: true });
}
});
},
getControlProps() {
return normalize.element({
id: dom.getControlId(scope),
...import_rating_group.parts.control.attrs,
dir: prop("dir"),
role: "radiogroup",
"aria-orientation": "horizontal",
"aria-labelledby": dom.getLabelId(scope),
"aria-readonly": (0, import_dom_query.ariaAttr)(readOnly),
"data-readonly": (0, import_dom_query.dataAttr)(readOnly),
"data-disabled": (0, import_dom_query.dataAttr)(disabled),
onPointerMove(event) {
if (!interactive) return;
if (event.pointerType === "touch") return;
send({ type: "GROUP_POINTER_OVER" });
},
onPointerLeave(event) {
if (!interactive) return;
if (event.pointerType === "touch") return;
send({ type: "GROUP_POINTER_LEAVE" });
}
});
},
getItemState,
getItemProps(props) {
const { index } = props;
const itemState = getItemState(props);
const valueText = translations.ratingValueText(index);
return normalize.element({
...import_rating_group.parts.item.attrs,
dir: prop("dir"),
id: dom.getItemId(scope, index.toString()),
role: "radio",
tabIndex: (() => {
if (readOnly) return itemState.checked ? 0 : void 0;
if (disabled) return void 0;
return itemState.checked ? 0 : -1;
})(),
"aria-roledescription": "rating",
"aria-label": valueText,
"aria-disabled": disabled,
"data-disabled": (0, import_dom_query.dataAttr)(disabled),
"data-readonly": (0, import_dom_query.dataAttr)(readOnly),
"aria-setsize": prop("count"),
"aria-checked": itemState.checked,
"data-checked": (0, import_dom_query.dataAttr)(itemState.checked),
"aria-posinset": index,
"data-highlighted": (0, import_dom_query.dataAttr)(itemState.highlighted),
"data-half": (0, import_dom_query.dataAttr)(itemState.half),
onPointerDown(event) {
if (!interactive) return;
if (!(0, import_dom_query.isLeftClick)(event)) return;
event.preventDefault();
},
onPointerMove(event) {
if (!interactive) return;
const point = (0, import_dom_query.getEventPoint)(event);
const relativePoint = (0, import_dom_query.getRelativePoint)(point, event.currentTarget);
const percentX = relativePoint.getPercentValue({
orientation: "horizontal",
dir: prop("dir")
});
const isMidway = percentX < 0.5;
send({ type: "POINTER_OVER", index, isMidway });
},
onKeyDown(event) {
if (event.defaultPrevented) return;
if (!interactive) return;
const keyMap = {
ArrowLeft() {
send({ type: "ARROW_LEFT" });
},
ArrowRight() {
send({ type: "ARROW_RIGHT" });
},
ArrowUp() {
send({ type: "ARROW_LEFT" });
},
ArrowDown() {
send({ type: "ARROW_RIGHT" });
},
Space() {
send({ type: "SPACE", value: index });
},
Home() {
send({ type: "HOME" });
},
End() {
send({ type: "END" });
}
};
const key = (0, import_dom_query.getEventKey)(event, { dir: prop("dir") });
const exec = keyMap[key];
if (exec) {
event.preventDefault();
exec(event);
}
},
onClick() {
if (!interactive) return;
send({ type: "CLICK", value: index });
},
onFocus() {
if (!interactive) return;
send({ type: "FOCUS" });
},
onBlur() {
if (!interactive) return;
send({ type: "BLUR" });
}
});
}
};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
connect
});