UNPKG

@zag-js/toggle-group

Version:

Core logic for the toggle widget implemented as a state machine

135 lines (134 loc) 4.65 kB
// src/toggle-group.connect.ts import { contains, dataAttr, getEventKey, getEventTarget, isSafari } from "@zag-js/dom-query"; import { parts } from "./toggle-group.anatomy.mjs"; import * as dom from "./toggle-group.dom.mjs"; function connect(service, normalize) { const { context, send, prop, scope } = service; const value = context.get("value"); const disabled = prop("disabled"); const isSingle = !prop("multiple"); const rovingFocus = prop("rovingFocus"); const isHorizontal = prop("orientation") === "horizontal"; function getItemState(props) { const id = dom.getItemId(scope, props.value); return { id, disabled: Boolean(props.disabled || disabled), pressed: !!value.includes(props.value), focused: context.get("focusedId") === id }; } return { value, setValue(value2) { send({ type: "VALUE.SET", value: value2 }); }, getRootProps() { return normalize.element({ ...parts.root.attrs, id: dom.getRootId(scope), dir: prop("dir"), role: isSingle ? "radiogroup" : "group", tabIndex: context.get("isTabbingBackward") ? -1 : 0, "data-disabled": dataAttr(disabled), "data-orientation": prop("orientation"), "data-focus": dataAttr(context.get("focusedId") != null), style: { outline: "none" }, onMouseDown() { if (disabled) return; send({ type: "ROOT.MOUSE_DOWN" }); }, onFocus(event) { if (disabled) return; if (event.currentTarget !== getEventTarget(event)) return; if (context.get("isClickFocus")) return; if (context.get("isTabbingBackward")) return; send({ type: "ROOT.FOCUS" }); }, onBlur(event) { const target = event.relatedTarget; if (contains(event.currentTarget, target)) return; if (disabled) return; send({ type: "ROOT.BLUR" }); } }); }, getItemState, getItemProps(props) { const itemState = getItemState(props); const rovingTabIndex = itemState.focused ? 0 : -1; return normalize.button({ ...parts.item.attrs, id: itemState.id, type: "button", "data-ownedby": dom.getRootId(scope), "data-focus": dataAttr(itemState.focused), disabled: itemState.disabled, tabIndex: rovingFocus ? rovingTabIndex : void 0, // radio role: isSingle ? "radio" : void 0, "aria-checked": isSingle ? itemState.pressed : void 0, "aria-pressed": isSingle ? void 0 : itemState.pressed, // "data-disabled": dataAttr(itemState.disabled), "data-orientation": prop("orientation"), dir: prop("dir"), "data-state": itemState.pressed ? "on" : "off", onFocus() { if (itemState.disabled) return; send({ type: "TOGGLE.FOCUS", id: itemState.id }); }, onClick(event) { if (itemState.disabled) return; send({ type: "TOGGLE.CLICK", id: itemState.id, value: props.value }); if (isSafari()) { event.currentTarget.focus({ preventScroll: true }); } }, onKeyDown(event) { if (event.defaultPrevented) return; if (!contains(event.currentTarget, getEventTarget(event))) return; if (itemState.disabled) return; const keyMap = { Tab(event2) { const isShiftTab = event2.shiftKey; send({ type: "TOGGLE.SHIFT_TAB", isShiftTab }); }, ArrowLeft() { if (!rovingFocus || !isHorizontal) return; send({ type: "TOGGLE.FOCUS_PREV" }); }, ArrowRight() { if (!rovingFocus || !isHorizontal) return; send({ type: "TOGGLE.FOCUS_NEXT" }); }, ArrowUp() { if (!rovingFocus || isHorizontal) return; send({ type: "TOGGLE.FOCUS_PREV" }); }, ArrowDown() { if (!rovingFocus || isHorizontal) return; send({ type: "TOGGLE.FOCUS_NEXT" }); }, Home() { if (!rovingFocus) return; send({ type: "TOGGLE.FOCUS_FIRST" }); }, End() { if (!rovingFocus) return; send({ type: "TOGGLE.FOCUS_LAST" }); } }; const exec = keyMap[getEventKey(event)]; if (exec) { exec(event); if (event.key !== "Tab") event.preventDefault(); } } }); } }; } export { connect };