package.dist.index.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of toggle-group Show documentation
Show all versions of toggle-group Show documentation
Core logic for the toggle widget implemented as a state machine
The newest version!
'use strict';
var anatomy$1 = require('@zag-js/anatomy');
var domEvent = require('@zag-js/dom-event');
var domQuery = require('@zag-js/dom-query');
var utils = require('@zag-js/utils');
var core = require('@zag-js/core');
var types = require('@zag-js/types');
// src/toggle-group.anatomy.ts
var anatomy = anatomy$1.createAnatomy("toggle-group").parts("root", "item");
var parts = anatomy.build();
var dom = domQuery.createScope({
getRootId: (ctx) => ctx.ids?.root ?? `toggle-group:${ctx.id}`,
getItemId: (ctx, value) => ctx.ids?.item?.(value) ?? `toggle-group:${ctx.id}:${value}`,
getRootEl: (ctx) => dom.getById(ctx, dom.getRootId(ctx)),
getElements: (ctx) => {
const ownerId = CSS.escape(dom.getRootId(ctx));
const selector = `[data-ownedby='${ownerId}']:not([data-disabled])`;
return domQuery.queryAll(dom.getRootEl(ctx), selector);
},
getFirstEl: (ctx) => utils.first(dom.getElements(ctx)),
getLastEl: (ctx) => utils.last(dom.getElements(ctx)),
getNextEl: (ctx, id) => domQuery.nextById(dom.getElements(ctx), id, ctx.currentLoopFocus),
getPrevEl: (ctx, id) => domQuery.prevById(dom.getElements(ctx), id, ctx.currentLoopFocus)
});
// src/toggle-group.connect.ts
function connect(state, send, normalize) {
const value = state.context.value;
const disabled = state.context.disabled;
const isSingle = !state.context.multiple;
const rovingFocus = state.context.rovingFocus;
const isHorizontal = state.context.orientation === "horizontal";
function getItemState(props2) {
const id = dom.getItemId(state.context, props2.value);
return {
id,
disabled: Boolean(props2.disabled || disabled),
pressed: !!value.includes(props2.value),
focused: state.context.focusedId === id
};
}
return {
value,
setValue(value2) {
send({ type: "VALUE.SET", value: value2 });
},
getRootProps() {
return normalize.element({
...parts.root.attrs,
id: dom.getRootId(state.context),
dir: state.context.dir,
role: isSingle ? "radiogroup" : "group",
tabIndex: state.context.isTabbingBackward ? -1 : 0,
"data-disabled": domQuery.dataAttr(disabled),
"data-orientation": state.context.orientation,
"data-focus": domQuery.dataAttr(state.context.focusedId != null),
style: { outline: "none" },
onMouseDown() {
if (disabled) return;
send("ROOT.MOUSE_DOWN");
},
onFocus(event) {
if (disabled) return;
const evt = event.nativeEvent || event;
if (!domQuery.isSelfTarget(evt) || !!state.context.isClickFocus || state.context.isTabbingBackward) return;
send("ROOT.FOCUS");
},
onBlur() {
if (disabled) return;
send("ROOT.BLUR");
}
});
},
getItemState,
getItemProps(props2) {
const itemState = getItemState(props2);
const rovingTabIndex = itemState.focused ? 0 : -1;
return normalize.button({
...parts.item.attrs,
id: itemState.id,
type: "button",
"data-ownedby": dom.getRootId(state.context),
"data-focus": domQuery.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": domQuery.dataAttr(itemState.disabled),
"data-orientation": state.context.orientation,
dir: state.context.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: props2.value });
if (domQuery.isSafari()) {
event.currentTarget.focus({ preventScroll: true });
}
},
onKeyDown(event) {
if (event.defaultPrevented) return;
if (!domQuery.isSelfTarget(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("TOGGLE.FOCUS_PREV");
},
ArrowRight() {
if (!rovingFocus || !isHorizontal) return;
send("TOGGLE.FOCUS_NEXT");
},
ArrowUp() {
if (!rovingFocus || isHorizontal) return;
send("TOGGLE.FOCUS_PREV");
},
ArrowDown() {
if (!rovingFocus || isHorizontal) return;
send("TOGGLE.FOCUS_NEXT");
},
Home() {
if (!rovingFocus) return;
send("TOGGLE.FOCUS_FIRST");
},
End() {
if (!rovingFocus) return;
send("TOGGLE.FOCUS_LAST");
}
};
const exec = keyMap[domEvent.getEventKey(event)];
if (exec) {
exec(event);
if (event.key !== "Tab") event.preventDefault();
}
}
});
}
};
}
var { not, and } = core.guards;
function machine(userContext) {
const ctx = utils.compact(userContext);
return core.createMachine(
{
id: "toggle-group",
initial: "idle",
context: {
value: [],
disabled: false,
orientation: "horizontal",
rovingFocus: true,
loopFocus: true,
...ctx,
focusedId: null,
isTabbingBackward: false,
isClickFocus: false,
isWithinToolbar: false
},
computed: {
currentLoopFocus: (ctx2) => ctx2.loopFocus && !ctx2.isWithinToolbar
},
entry: ["checkIfWithinToolbar"],
on: {
"VALUE.SET": {
actions: ["setValue"]
},
"TOGGLE.CLICK": {
actions: ["setValue"]
},
"ROOT.MOUSE_DOWN": {
actions: ["setClickFocus"]
}
},
states: {
idle: {
on: {
"ROOT.FOCUS": {
target: "focused",
guard: not(and("isClickFocus", "isTabbingBackward")),
actions: ["focusFirstToggle", "clearClickFocus"]
},
"TOGGLE.FOCUS": {
target: "focused",
actions: ["setFocusedId"]
}
}
},
focused: {
on: {
"ROOT.BLUR": {
target: "idle",
actions: ["clearIsTabbingBackward"]
},
"TOGGLE.FOCUS": {
actions: ["setFocusedId"]
},
"TOGGLE.FOCUS_NEXT": {
actions: ["focusNextToggle"]
},
"TOGGLE.FOCUS_PREV": {
actions: ["focusPrevToggle"]
},
"TOGGLE.FOCUS_FIRST": {
actions: ["focusFirstToggle"]
},
"TOGGLE.FOCUS_LAST": {
actions: ["focusLastToggle"]
},
"TOGGLE.SHIFT_TAB": {
target: "idle",
actions: ["setIsTabbingBackward"]
}
}
}
}
},
{
guards: {
isClickFocus: (ctx2) => ctx2.isClickFocus,
isTabbingBackward: (ctx2) => ctx2.isTabbingBackward
},
actions: {
setIsTabbingBackward(ctx2) {
ctx2.isTabbingBackward = true;
},
clearIsTabbingBackward(ctx2) {
ctx2.isTabbingBackward = false;
},
setClickFocus(ctx2) {
ctx2.isClickFocus = true;
},
clearClickFocus(ctx2) {
ctx2.isClickFocus = false;
},
checkIfWithinToolbar(ctx2) {
const closestToolbar = dom.getRootEl(ctx2)?.closest("[role=toolbar]");
ctx2.isWithinToolbar = !!closestToolbar;
},
setFocusedId(ctx2, evt) {
ctx2.focusedId = evt.id;
},
clearFocusedId(ctx2) {
ctx2.focusedId = null;
},
setValue(ctx2, evt) {
if (!evt.value) return;
let next = Array.from(ctx2.value);
if (ctx2.multiple) {
next = next.includes(evt.value) ? utils.remove(next, evt.value) : utils.add(next, evt.value);
} else {
next = utils.isEqual(ctx2.value, [evt.value]) ? [] : [evt.value];
}
set.value(ctx2, next);
},
focusNextToggle(ctx2) {
domQuery.raf(() => {
if (!ctx2.focusedId) return;
dom.getNextEl(ctx2, ctx2.focusedId)?.focus({ preventScroll: true });
});
},
focusPrevToggle(ctx2) {
domQuery.raf(() => {
if (!ctx2.focusedId) return;
dom.getPrevEl(ctx2, ctx2.focusedId)?.focus({ preventScroll: true });
});
},
focusFirstToggle(ctx2) {
domQuery.raf(() => {
dom.getFirstEl(ctx2)?.focus({ preventScroll: true });
});
},
focusLastToggle(ctx2) {
domQuery.raf(() => {
dom.getLastEl(ctx2)?.focus({ preventScroll: true });
});
}
}
}
);
}
var invoke = {
change(ctx) {
ctx.onValueChange?.({ value: Array.from(ctx.value) });
}
};
var set = {
value(ctx, value) {
if (utils.isEqual(ctx.value, value)) return;
ctx.value = value;
invoke.change(ctx);
}
};
var props = types.createProps()([
"dir",
"disabled",
"getRootNode",
"id",
"ids",
"loopFocus",
"multiple",
"onValueChange",
"orientation",
"rovingFocus",
"value"
]);
var splitProps = utils.createSplitProps(props);
var itemProps = types.createProps()(["value", "disabled"]);
var splitItemProps = utils.createSplitProps(itemProps);
exports.anatomy = anatomy;
exports.connect = connect;
exports.itemProps = itemProps;
exports.machine = machine;
exports.props = props;
exports.splitItemProps = splitItemProps;
exports.splitProps = splitProps;
© 2015 - 2025 Weber Informatics LLC | Privacy Policy