UNPKG

@zag-js/radio-group

Version:

Core logic for the radio group widget implemented as a state machine

254 lines (252 loc) • 10.3 kB
"use strict"; 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/radio-group.connect.ts var radio_group_connect_exports = {}; __export(radio_group_connect_exports, { connect: () => connect }); module.exports = __toCommonJS(radio_group_connect_exports); var import_dom_query = require("@zag-js/dom-query"); var import_focus_visible = require("@zag-js/focus-visible"); var import_utils = require("@zag-js/utils"); var import_radio_group = require("./radio-group.anatomy.js"); var dom = __toESM(require("./radio-group.dom.js")); function connect(service, normalize) { const { context, send, computed, prop, scope } = service; const groupDisabled = computed("isDisabled"); const groupInvalid = prop("invalid"); const readOnly = prop("readOnly"); function getItemState(props) { return { value: props.value, invalid: !!props.invalid || !!groupInvalid, disabled: !!props.disabled || groupDisabled, checked: context.get("value") === props.value, focused: context.get("focusedValue") === props.value, focusVisible: context.get("focusVisibleValue") === props.value, hovered: context.get("hoveredValue") === props.value, active: context.get("activeValue") === props.value }; } function getItemDataAttrs(props) { const itemState = getItemState(props); return { "data-focus": (0, import_dom_query.dataAttr)(itemState.focused), "data-focus-visible": (0, import_dom_query.dataAttr)(itemState.focusVisible), "data-disabled": (0, import_dom_query.dataAttr)(itemState.disabled), "data-readonly": (0, import_dom_query.dataAttr)(readOnly), "data-state": itemState.checked ? "checked" : "unchecked", "data-hover": (0, import_dom_query.dataAttr)(itemState.hovered), "data-invalid": (0, import_dom_query.dataAttr)(itemState.invalid), "data-orientation": prop("orientation"), "data-ssr": (0, import_dom_query.dataAttr)(context.get("ssr")) }; } const focus = () => { const nodeToFocus = dom.getFirstEnabledAndCheckedInputEl(scope) ?? dom.getFirstEnabledInputEl(scope); nodeToFocus?.focus(); }; return { focus, value: context.get("value"), setValue(value) { send({ type: "SET_VALUE", value, isTrusted: false }); }, clearValue() { send({ type: "SET_VALUE", value: null, isTrusted: false }); }, getRootProps() { return normalize.element({ ...import_radio_group.parts.root.attrs, role: "radiogroup", id: dom.getRootId(scope), "aria-labelledby": dom.getLabelId(scope), "aria-required": prop("required") || void 0, "aria-disabled": groupDisabled || void 0, "aria-readonly": readOnly || void 0, "data-orientation": prop("orientation"), "data-disabled": (0, import_dom_query.dataAttr)(groupDisabled), "data-invalid": (0, import_dom_query.dataAttr)(groupInvalid), "data-required": (0, import_dom_query.dataAttr)(prop("required")), "aria-orientation": prop("orientation"), dir: prop("dir"), style: { position: "relative" } }); }, getLabelProps() { return normalize.element({ ...import_radio_group.parts.label.attrs, dir: prop("dir"), "data-orientation": prop("orientation"), "data-disabled": (0, import_dom_query.dataAttr)(groupDisabled), "data-invalid": (0, import_dom_query.dataAttr)(groupInvalid), "data-required": (0, import_dom_query.dataAttr)(prop("required")), id: dom.getLabelId(scope), onClick: focus }); }, getItemState, getItemProps(props) { const itemState = getItemState(props); return normalize.label({ ...import_radio_group.parts.item.attrs, dir: prop("dir"), id: dom.getItemId(scope, props.value), htmlFor: dom.getItemHiddenInputId(scope, props.value), ...getItemDataAttrs(props), onPointerMove() { if (itemState.disabled) return; if (itemState.hovered) return; send({ type: "SET_HOVERED", value: props.value, hovered: true }); }, onPointerLeave() { if (itemState.disabled) return; send({ type: "SET_HOVERED", value: null }); }, onPointerDown(event) { if (itemState.disabled) return; if (!(0, import_dom_query.isLeftClick)(event)) return; if (itemState.focused && event.pointerType === "mouse") { event.preventDefault(); } send({ type: "SET_ACTIVE", value: props.value, active: true }); }, onPointerUp() { if (itemState.disabled) return; send({ type: "SET_ACTIVE", value: null }); }, onClick() { if (!itemState.disabled && (0, import_dom_query.isSafari)()) { dom.getItemHiddenInputEl(scope, props.value)?.focus(); } } }); }, getItemTextProps(props) { return normalize.element({ ...import_radio_group.parts.itemText.attrs, dir: prop("dir"), id: dom.getItemLabelId(scope, props.value), ...getItemDataAttrs(props) }); }, getItemControlProps(props) { const itemState = getItemState(props); return normalize.element({ ...import_radio_group.parts.itemControl.attrs, dir: prop("dir"), id: dom.getItemControlId(scope, props.value), "data-active": (0, import_dom_query.dataAttr)(itemState.active), "aria-hidden": true, ...getItemDataAttrs(props) }); }, getItemHiddenInputProps(props) { const itemState = getItemState(props); return normalize.input({ "data-ownedby": dom.getRootId(scope), id: dom.getItemHiddenInputId(scope, props.value), type: "radio", name: prop("name") || prop("id"), form: prop("form"), value: props.value, required: prop("required"), "aria-labelledby": dom.getItemLabelId(scope, props.value), "aria-invalid": itemState.invalid || void 0, onClick(event) { if (readOnly) { event.preventDefault(); return; } if (event.currentTarget.checked) { send({ type: "SET_VALUE", value: props.value, isTrusted: true }); } }, onBlur() { send({ type: "SET_FOCUSED", value: null, focused: false, focusVisible: false }); }, onFocus() { const focusVisible = (0, import_focus_visible.isFocusVisible)(); send({ type: "SET_FOCUSED", value: props.value, focused: true, focusVisible }); }, onKeyDown(event) { if (event.defaultPrevented) return; if (event.key === " ") { send({ type: "SET_ACTIVE", value: props.value, active: true }); } }, onKeyUp(event) { if (event.defaultPrevented) return; if (event.key === " ") { send({ type: "SET_ACTIVE", value: null }); } }, disabled: itemState.disabled || readOnly, defaultChecked: itemState.checked, style: import_dom_query.visuallyHiddenStyle }); }, getIndicatorProps() { const rect = context.get("indicatorRect"); const animateIndicator = context.get("animateIndicator"); return normalize.element({ id: dom.getIndicatorId(scope), ...import_radio_group.parts.indicator.attrs, dir: prop("dir"), hidden: context.get("value") == null || isRectEmpty(rect), "data-disabled": (0, import_dom_query.dataAttr)(groupDisabled), "data-orientation": prop("orientation"), onTransitionEnd(event) { if ((0, import_dom_query.getEventTarget)(event) !== event.currentTarget) return; send({ type: "INDICATOR_TRANSITION_END" }); }, style: { "--transition-property": "left, top, width, height", "--left": (0, import_utils.toPx)(rect?.x), "--top": (0, import_utils.toPx)(rect?.y), "--width": (0, import_utils.toPx)(rect?.width), "--height": (0, import_utils.toPx)(rect?.height), position: "absolute", willChange: animateIndicator ? "var(--transition-property)" : "auto", transitionProperty: animateIndicator ? "var(--transition-property)" : "none", transitionDuration: animateIndicator ? "var(--transition-duration, 150ms)" : "0ms", transitionTimingFunction: "var(--transition-timing-function)", [prop("orientation") === "horizontal" ? "left" : "top"]: prop("orientation") === "horizontal" ? "var(--left)" : "var(--top)" } }); } }; } var isRectEmpty = (rect) => rect == null || rect.width === 0 && rect.height === 0 && rect.x === 0 && rect.y === 0; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { connect });