UNPKG

@zag-js/accordion

Version:

Core logic for the accordion widget implemented as a state machine

151 lines (150 loc) 5 kB
// src/accordion.connect.ts import { dataAttr, getEventKey, isSafari } from "@zag-js/dom-query"; import { parts } from "./accordion.anatomy.mjs"; import * as dom from "./accordion.dom.mjs"; function connect(service, normalize) { const { send, context, prop, scope, computed } = service; const focusedValue = context.get("focusedValue"); const value = context.get("value"); const multiple = prop("multiple"); function setValue(value2) { let nextValue = value2; if (!multiple && nextValue.length > 1) { nextValue = [nextValue[0]]; } send({ type: "VALUE.SET", value: nextValue }); } function getItemState(props) { return { expanded: value.includes(props.value), focused: focusedValue === props.value, disabled: Boolean(props.disabled ?? prop("disabled")) }; } return { focusedValue, value, setValue, getItemState, getRootProps() { return normalize.element({ ...parts.root.attrs, dir: prop("dir"), id: dom.getRootId(scope), "data-orientation": prop("orientation") }); }, getItemProps(props) { const itemState = getItemState(props); return normalize.element({ ...parts.item.attrs, dir: prop("dir"), id: dom.getItemId(scope, props.value), "data-state": itemState.expanded ? "open" : "closed", "data-focus": dataAttr(itemState.focused), "data-disabled": dataAttr(itemState.disabled), "data-orientation": prop("orientation") }); }, getItemContentProps(props) { const itemState = getItemState(props); return normalize.element({ ...parts.itemContent.attrs, dir: prop("dir"), role: "region", id: dom.getItemContentId(scope, props.value), "aria-labelledby": dom.getItemTriggerId(scope, props.value), hidden: !itemState.expanded, "data-state": itemState.expanded ? "open" : "closed", "data-disabled": dataAttr(itemState.disabled), "data-focus": dataAttr(itemState.focused), "data-orientation": prop("orientation") }); }, getItemIndicatorProps(props) { const itemState = getItemState(props); return normalize.element({ ...parts.itemIndicator.attrs, dir: prop("dir"), "aria-hidden": true, "data-state": itemState.expanded ? "open" : "closed", "data-disabled": dataAttr(itemState.disabled), "data-focus": dataAttr(itemState.focused), "data-orientation": prop("orientation") }); }, getItemTriggerProps(props) { const { value: value2 } = props; const itemState = getItemState(props); return normalize.button({ ...parts.itemTrigger.attrs, type: "button", dir: prop("dir"), id: dom.getItemTriggerId(scope, value2), "aria-controls": dom.getItemContentId(scope, value2), "data-controls": dom.getItemContentId(scope, value2), "aria-expanded": itemState.expanded, disabled: itemState.disabled, "data-orientation": prop("orientation"), "data-state": itemState.expanded ? "open" : "closed", "data-focus": dataAttr(itemState.focused), "data-ownedby": dom.getRootId(scope), onFocus() { if (itemState.disabled) return; send({ type: "TRIGGER.FOCUS", value: value2 }); }, onBlur() { if (itemState.disabled) return; send({ type: "TRIGGER.BLUR" }); }, onClick(event) { if (itemState.disabled) return; if (isSafari()) { event.currentTarget.focus(); } send({ type: "TRIGGER.CLICK", value: value2 }); }, onKeyDown(event) { if (event.defaultPrevented) return; if (itemState.disabled) return; const keyMap = { ArrowDown() { if (computed("isHorizontal")) return; send({ type: "GOTO.NEXT", value: value2 }); }, ArrowUp() { if (computed("isHorizontal")) return; send({ type: "GOTO.PREV", value: value2 }); }, ArrowRight() { if (!computed("isHorizontal")) return; send({ type: "GOTO.NEXT", value: value2 }); }, ArrowLeft() { if (!computed("isHorizontal")) return; send({ type: "GOTO.PREV", value: value2 }); }, Home() { send({ type: "GOTO.FIRST", value: value2 }); }, End() { send({ type: "GOTO.LAST", value: value2 }); } }; const key = getEventKey(event, { dir: prop("dir"), orientation: prop("orientation") }); const exec = keyMap[key]; if (exec) { exec(event); event.preventDefault(); } } }); } }; } export { connect };