UNPKG

@zag-js/tabs

Version:

Core logic for the tabs widget implemented as a state machine

231 lines (229 loc) • 8.65 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/tabs.connect.ts var tabs_connect_exports = {}; __export(tabs_connect_exports, { connect: () => connect }); module.exports = __toCommonJS(tabs_connect_exports); var import_dom_query = require("@zag-js/dom-query"); var import_utils = require("@zag-js/utils"); var import_tabs = require("./tabs.anatomy.js"); var dom = __toESM(require("./tabs.dom.js")); function connect(service, normalize) { const { state, send, context, prop, scope } = service; const translations = prop("translations"); const focused = state.matches("focused"); const isVertical = prop("orientation") === "vertical"; const isHorizontal = prop("orientation") === "horizontal"; const composite = prop("composite"); function getTriggerState(props) { return { selected: context.get("value") === props.value, focused: context.get("focusedValue") === props.value, disabled: !!props.disabled }; } return { value: context.get("value"), focusedValue: context.get("focusedValue"), setValue(value) { send({ type: "SET_VALUE", value }); }, clearValue() { send({ type: "CLEAR_VALUE" }); }, setIndicatorRect(value) { const id = dom.getTriggerId(scope, value); send({ type: "SET_INDICATOR_RECT", id }); }, syncTabIndex() { send({ type: "SYNC_TAB_INDEX" }); }, selectNext(fromValue) { send({ type: "TAB_FOCUS", value: fromValue, src: "selectNext" }); send({ type: "ARROW_NEXT", src: "selectNext" }); }, selectPrev(fromValue) { send({ type: "TAB_FOCUS", value: fromValue, src: "selectPrev" }); send({ type: "ARROW_PREV", src: "selectPrev" }); }, focus() { const value = context.get("value"); if (!value) return; dom.getTriggerEl(scope, value)?.focus(); }, getRootProps() { return normalize.element({ ...import_tabs.parts.root.attrs, id: dom.getRootId(scope), "data-orientation": prop("orientation"), "data-focus": (0, import_dom_query.dataAttr)(focused), dir: prop("dir") }); }, getListProps() { return normalize.element({ ...import_tabs.parts.list.attrs, id: dom.getListId(scope), role: "tablist", dir: prop("dir"), "data-focus": (0, import_dom_query.dataAttr)(focused), "aria-orientation": prop("orientation"), "data-orientation": prop("orientation"), "aria-label": translations?.listLabel, onKeyDown(event) { if (event.defaultPrevented) return; if ((0, import_dom_query.isComposingEvent)(event)) return; if (!(0, import_dom_query.contains)(event.currentTarget, (0, import_dom_query.getEventTarget)(event))) return; const keyMap = { ArrowDown() { if (isHorizontal) return; send({ type: "ARROW_NEXT", key: "ArrowDown" }); }, ArrowUp() { if (isHorizontal) return; send({ type: "ARROW_PREV", key: "ArrowUp" }); }, ArrowLeft() { if (isVertical) return; send({ type: "ARROW_PREV", key: "ArrowLeft" }); }, ArrowRight() { if (isVertical) return; send({ type: "ARROW_NEXT", key: "ArrowRight" }); }, Home() { send({ type: "HOME" }); }, End() { send({ type: "END" }); } }; let key = (0, import_dom_query.getEventKey)(event, { dir: prop("dir"), orientation: prop("orientation") }); const exec = keyMap[key]; if (exec) { event.preventDefault(); exec(event); return; } } }); }, getTriggerState, getTriggerProps(props) { const { value, disabled } = props; const triggerState = getTriggerState(props); return normalize.button({ ...import_tabs.parts.trigger.attrs, role: "tab", type: "button", disabled, dir: prop("dir"), "data-orientation": prop("orientation"), "data-disabled": (0, import_dom_query.dataAttr)(disabled), "aria-disabled": disabled, "data-value": value, "aria-selected": triggerState.selected, "data-selected": (0, import_dom_query.dataAttr)(triggerState.selected), "data-focus": (0, import_dom_query.dataAttr)(triggerState.focused), "aria-controls": triggerState.selected ? dom.getContentId(scope, value) : void 0, "data-ownedby": dom.getListId(scope), "data-ssr": (0, import_dom_query.dataAttr)(context.get("ssr")), id: dom.getTriggerId(scope, value), tabIndex: triggerState.selected && composite ? 0 : -1, onFocus() { send({ type: "TAB_FOCUS", value }); }, onBlur(event) { const target = event.relatedTarget; if (target?.getAttribute("role") !== "tab") { send({ type: "TAB_BLUR" }); } }, onClick(event) { if (event.defaultPrevented) return; if ((0, import_dom_query.isOpeningInNewTab)(event)) return; if (disabled) return; if ((0, import_dom_query.isSafari)()) { event.currentTarget.focus(); } send({ type: "TAB_CLICK", value }); } }); }, getContentProps(props) { const { value } = props; const selected = context.get("value") === value; return normalize.element({ ...import_tabs.parts.content.attrs, dir: prop("dir"), id: dom.getContentId(scope, value), tabIndex: composite ? 0 : -1, "aria-labelledby": dom.getTriggerId(scope, value), role: "tabpanel", "data-ownedby": dom.getListId(scope), "data-selected": (0, import_dom_query.dataAttr)(selected), "data-orientation": prop("orientation"), hidden: !selected }); }, getIndicatorProps() { const rect = context.get("indicatorRect"); const rectIsEmpty = rect == null || rect.width === 0 && rect.height === 0 && rect.x === 0 && rect.y === 0; return normalize.element({ id: dom.getIndicatorId(scope), ...import_tabs.parts.indicator.attrs, dir: prop("dir"), "data-orientation": prop("orientation"), hidden: rectIsEmpty, style: { "--transition-property": "left, right, top, bottom, 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: "var(--transition-property)", transitionProperty: "var(--transition-property)", transitionDuration: "var(--transition-duration, 150ms)", transitionTimingFunction: "var(--transition-timing-function)", [isHorizontal ? "left" : "top"]: isHorizontal ? "var(--left)" : "var(--top)" } }); } }; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { connect });