@zag-js/radio-group
Advanced tools
Comparing version
import * as _zag_js_anatomy from '@zag-js/anatomy'; | ||
import { RequiredBy, PropTypes, DirectionProperty, CommonProperties, NormalizeProps } from '@zag-js/types'; | ||
import { DirectionProperty, CommonProperties, PropTypes, RequiredBy, NormalizeProps } from '@zag-js/types'; | ||
import * as _zag_js_core from '@zag-js/core'; | ||
import { Machine, StateMachine } from '@zag-js/core'; | ||
import { Service, EventObject } from '@zag-js/core'; | ||
@@ -9,3 +9,3 @@ declare const anatomy: _zag_js_anatomy.AnatomyInstance<"root" | "label" | "item" | "itemText" | "itemControl" | "indicator">; | ||
interface ValueChangeDetails { | ||
value: string; | ||
value: string | null; | ||
} | ||
@@ -21,3 +21,3 @@ type ElementIds = Partial<{ | ||
}>; | ||
interface PublicContext extends DirectionProperty, CommonProperties { | ||
interface RadioGroupProps extends DirectionProperty, CommonProperties { | ||
/** | ||
@@ -28,6 +28,11 @@ * The ids of the elements in the radio. Useful for composition. | ||
/** | ||
* The value of the checked radio | ||
* The controlled value of the radio group | ||
*/ | ||
value: string | null; | ||
value?: string | null | undefined; | ||
/** | ||
* The initial value of the checked radio when rendered. | ||
* Use when you don't need to control the value of the radio group. | ||
*/ | ||
defaultValue?: string | null | undefined; | ||
/** | ||
* The name of the input fields in the radio | ||
@@ -51,5 +56,4 @@ * (Useful for form submission). | ||
* Function called once a radio is checked | ||
* @param value the value of the checked radio | ||
*/ | ||
onValueChange?(details: ValueChangeDetails): void; | ||
onValueChange?: ((details: ValueChangeDetails) => void) | undefined; | ||
/** | ||
@@ -60,8 +64,49 @@ * Orientation of the radio group | ||
} | ||
interface IndicatorRect { | ||
left: string; | ||
top: string; | ||
width: string; | ||
height: string; | ||
} | ||
interface PrivateContext { | ||
/** | ||
* The value of the checked radio | ||
*/ | ||
value: string | null; | ||
/** | ||
* The id of the active radio | ||
*/ | ||
activeValue: string | null; | ||
/** | ||
* The id of the focused radio | ||
*/ | ||
focusedValue: string | null; | ||
/** | ||
* The id of the hovered radio | ||
*/ | ||
hoveredValue: string | null; | ||
/** | ||
* The active tab indicator's dom rect | ||
*/ | ||
indicatorRect: Partial<IndicatorRect>; | ||
/** | ||
* Whether the active tab indicator's rect can transition | ||
*/ | ||
canIndicatorTransition: boolean; | ||
/** | ||
* Whether the radio group's fieldset is disabled | ||
*/ | ||
fieldsetDisabled: boolean; | ||
/** | ||
* Whether the radio group is in focus | ||
*/ | ||
focusVisible: boolean; | ||
/** | ||
* Whether the radio group is in server-side rendering | ||
*/ | ||
ssr: boolean; | ||
} | ||
type UserDefinedContext = RequiredBy<PublicContext, "id">; | ||
type PropsWithDefault = "orientation"; | ||
type ComputedContext = Readonly<{ | ||
/** | ||
* @computed | ||
* Whether the radio group is disabled | ||
@@ -71,10 +116,20 @@ */ | ||
}>; | ||
interface MachineContext extends PublicContext, PrivateContext, ComputedContext { | ||
interface Refs { | ||
/** | ||
* Function to clean up the observer for the active tab's rect | ||
*/ | ||
indicatorCleanup: VoidFunction | null; | ||
} | ||
interface MachineState { | ||
value: "idle"; | ||
interface RadioGroupSchema { | ||
state: "idle"; | ||
props: RequiredBy<RadioGroupProps, PropsWithDefault>; | ||
context: PrivateContext; | ||
computed: ComputedContext; | ||
refs: Refs; | ||
event: EventObject; | ||
action: string; | ||
effect: string; | ||
guard: string; | ||
} | ||
type State = StateMachine.State<MachineContext, MachineState>; | ||
type Send = StateMachine.Send<StateMachine.AnyEventObject>; | ||
type Service = Machine<MachineContext, MachineState, StateMachine.AnyEventObject>; | ||
type RadioGroupService = Service<RadioGroupSchema>; | ||
interface ItemProps { | ||
@@ -111,3 +166,3 @@ value: string; | ||
} | ||
interface MachineApi<T extends PropTypes = PropTypes> { | ||
interface RadioGroupApi<T extends PropTypes = PropTypes> { | ||
/** | ||
@@ -142,11 +197,11 @@ * The current value of the radio group | ||
declare function connect<T extends PropTypes>(state: State, send: Send, normalize: NormalizeProps<T>): MachineApi<T>; | ||
declare function connect<T extends PropTypes>(service: RadioGroupService, normalize: NormalizeProps<T>): RadioGroupApi<T>; | ||
declare function machine(userContext: UserDefinedContext): _zag_js_core.Machine<MachineContext, MachineState, _zag_js_core.StateMachine.AnyEventObject>; | ||
declare const machine: _zag_js_core.MachineConfig<RadioGroupSchema>; | ||
declare const props: ("disabled" | "form" | "dir" | "id" | "name" | "value" | "orientation" | "getRootNode" | "ids" | "readOnly" | "onValueChange")[]; | ||
declare const splitProps: <Props extends Partial<UserDefinedContext>>(props: Props) => [Partial<UserDefinedContext>, Omit<Props, "disabled" | "form" | "dir" | "id" | "name" | "value" | "orientation" | "getRootNode" | "ids" | "readOnly" | "onValueChange">]; | ||
declare const props: (keyof RadioGroupProps)[]; | ||
declare const splitProps: <Props extends Partial<RadioGroupProps>>(props: Props) => [Partial<RadioGroupProps>, Omit<Props, keyof RadioGroupProps>]; | ||
declare const itemProps: (keyof ItemProps)[]; | ||
declare const splitItemProps: <Props extends ItemProps>(props: Props) => [ItemProps, Omit<Props, keyof ItemProps>]; | ||
export { type MachineApi as Api, type UserDefinedContext as Context, type ElementIds, type ItemProps, type ItemState, type Service, type ValueChangeDetails, anatomy, connect, itemProps, machine, props, splitItemProps, splitProps }; | ||
export { type RadioGroupApi as Api, type ElementIds, type ItemProps, type ItemState, type RadioGroupProps as Props, type RadioGroupService as Service, type ValueChangeDetails, anatomy, connect, itemProps, machine, props, splitItemProps, splitProps }; |
@@ -21,47 +21,40 @@ 'use strict'; | ||
var parts = anatomy.build(); | ||
var dom = domQuery.createScope({ | ||
getRootId: (ctx) => ctx.ids?.root ?? `radio-group:${ctx.id}`, | ||
getLabelId: (ctx) => ctx.ids?.label ?? `radio-group:${ctx.id}:label`, | ||
getItemId: (ctx, value) => ctx.ids?.item?.(value) ?? `radio-group:${ctx.id}:radio:${value}`, | ||
getItemHiddenInputId: (ctx, value) => ctx.ids?.itemHiddenInput?.(value) ?? `radio-group:${ctx.id}:radio:input:${value}`, | ||
getItemControlId: (ctx, value) => ctx.ids?.itemControl?.(value) ?? `radio-group:${ctx.id}:radio:control:${value}`, | ||
getItemLabelId: (ctx, value) => ctx.ids?.itemLabel?.(value) ?? `radio-group:${ctx.id}:radio:label:${value}`, | ||
getIndicatorId: (ctx) => ctx.ids?.indicator ?? `radio-group:${ctx.id}:indicator`, | ||
getRootEl: (ctx) => dom.getById(ctx, dom.getRootId(ctx)), | ||
getItemHiddenInputEl: (ctx, value) => dom.getById(ctx, dom.getItemHiddenInputId(ctx, value)), | ||
getIndicatorEl: (ctx) => dom.getById(ctx, dom.getIndicatorId(ctx)), | ||
getFirstEnabledInputEl: (ctx) => dom.getRootEl(ctx)?.querySelector("input:not(:disabled)"), | ||
getFirstEnabledAndCheckedInputEl: (ctx) => dom.getRootEl(ctx)?.querySelector("input:not(:disabled):checked"), | ||
getInputEls: (ctx) => { | ||
const ownerId = CSS.escape(dom.getRootId(ctx)); | ||
const selector = `input[type=radio][data-ownedby='${ownerId}']:not([disabled])`; | ||
return domQuery.queryAll(dom.getRootEl(ctx), selector); | ||
}, | ||
getActiveRadioEl: (ctx) => { | ||
if (!ctx.value) return; | ||
return dom.getById(ctx, dom.getItemId(ctx, ctx.value)); | ||
}, | ||
getOffsetRect: (el) => ({ | ||
left: el?.offsetLeft ?? 0, | ||
top: el?.offsetTop ?? 0, | ||
width: el?.offsetWidth ?? 0, | ||
height: el?.offsetHeight ?? 0 | ||
}), | ||
getRectById: (ctx, id) => { | ||
const radioEl = dom.getById(ctx, dom.getItemId(ctx, id)); | ||
if (!radioEl) return; | ||
return dom.resolveRect(dom.getOffsetRect(radioEl)); | ||
}, | ||
resolveRect: (rect) => ({ | ||
width: `${rect.width}px`, | ||
height: `${rect.height}px`, | ||
left: `${rect.left}px`, | ||
top: `${rect.top}px` | ||
}) | ||
var getRootId = (ctx) => ctx.ids?.root ?? `radio-group:${ctx.id}`; | ||
var getLabelId = (ctx) => ctx.ids?.label ?? `radio-group:${ctx.id}:label`; | ||
var getItemId = (ctx, value) => ctx.ids?.item?.(value) ?? `radio-group:${ctx.id}:radio:${value}`; | ||
var getItemHiddenInputId = (ctx, value) => ctx.ids?.itemHiddenInput?.(value) ?? `radio-group:${ctx.id}:radio:input:${value}`; | ||
var getItemControlId = (ctx, value) => ctx.ids?.itemControl?.(value) ?? `radio-group:${ctx.id}:radio:control:${value}`; | ||
var getItemLabelId = (ctx, value) => ctx.ids?.itemLabel?.(value) ?? `radio-group:${ctx.id}:radio:label:${value}`; | ||
var getIndicatorId = (ctx) => ctx.ids?.indicator ?? `radio-group:${ctx.id}:indicator`; | ||
var getRootEl = (ctx) => ctx.getById(getRootId(ctx)); | ||
var getIndicatorEl = (ctx) => ctx.getById(getIndicatorId(ctx)); | ||
var getFirstEnabledInputEl = (ctx) => getRootEl(ctx)?.querySelector("input:not(:disabled)"); | ||
var getFirstEnabledAndCheckedInputEl = (ctx) => getRootEl(ctx)?.querySelector("input:not(:disabled):checked"); | ||
var getInputEls = (ctx) => { | ||
const ownerId = CSS.escape(getRootId(ctx)); | ||
const selector = `input[type=radio][data-ownedby='${ownerId}']:not([disabled])`; | ||
return domQuery.queryAll(getRootEl(ctx), selector); | ||
}; | ||
var getRadioEl = (ctx, value) => { | ||
if (!value) return; | ||
return ctx.getById(getItemId(ctx, value)); | ||
}; | ||
var getOffsetRect = (el) => ({ | ||
left: el?.offsetLeft ?? 0, | ||
top: el?.offsetTop ?? 0, | ||
width: el?.offsetWidth ?? 0, | ||
height: el?.offsetHeight ?? 0 | ||
}); | ||
var resolveRect = (rect) => ({ | ||
width: `${rect.width}px`, | ||
height: `${rect.height}px`, | ||
left: `${rect.left}px`, | ||
top: `${rect.top}px` | ||
}); | ||
// src/radio-group.connect.ts | ||
function connect(state, send, normalize) { | ||
const groupDisabled = state.context.isDisabled; | ||
const readOnly = state.context.readOnly; | ||
function connect(service, normalize) { | ||
const { context, send, computed, prop, scope } = service; | ||
const groupDisabled = computed("isDisabled"); | ||
const readOnly = prop("readOnly"); | ||
function getItemState(props2) { | ||
@@ -71,6 +64,6 @@ return { | ||
disabled: !!props2.disabled || groupDisabled, | ||
checked: state.context.value === props2.value, | ||
focused: state.context.focusedValue === props2.value, | ||
hovered: state.context.hoveredValue === props2.value, | ||
active: state.context.activeValue === props2.value | ||
checked: context.get("value") === props2.value, | ||
focused: context.get("focusedValue") === props2.value, | ||
hovered: context.get("hoveredValue") === props2.value, | ||
active: context.get("activeValue") === props2.value | ||
}; | ||
@@ -82,3 +75,3 @@ } | ||
"data-focus": domQuery.dataAttr(radioState.focused), | ||
"data-focus-visible": domQuery.dataAttr(radioState.focused && state.context.focusVisible), | ||
"data-focus-visible": domQuery.dataAttr(radioState.focused && context.get("focusVisible")), | ||
"data-disabled": domQuery.dataAttr(radioState.disabled), | ||
@@ -89,8 +82,8 @@ "data-readonly": domQuery.dataAttr(readOnly), | ||
"data-invalid": domQuery.dataAttr(radioState.invalid), | ||
"data-orientation": state.context.orientation, | ||
"data-ssr": domQuery.dataAttr(state.context.ssr) | ||
"data-orientation": prop("orientation"), | ||
"data-ssr": domQuery.dataAttr(context.get("ssr")) | ||
}; | ||
} | ||
const focus = () => { | ||
const firstEnabledAndCheckedInput = dom.getFirstEnabledAndCheckedInputEl(state.context); | ||
const firstEnabledAndCheckedInput = getFirstEnabledAndCheckedInputEl(scope); | ||
if (firstEnabledAndCheckedInput) { | ||
@@ -100,3 +93,3 @@ firstEnabledAndCheckedInput.focus(); | ||
} | ||
const firstEnabledInput = dom.getFirstEnabledInputEl(state.context); | ||
const firstEnabledInput = getFirstEnabledInputEl(scope); | ||
firstEnabledInput?.focus(); | ||
@@ -106,3 +99,3 @@ }; | ||
focus, | ||
value: state.context.value, | ||
value: context.get("value"), | ||
setValue(value) { | ||
@@ -118,8 +111,8 @@ send({ type: "SET_VALUE", value, isTrusted: false }); | ||
role: "radiogroup", | ||
id: dom.getRootId(state.context), | ||
"aria-labelledby": dom.getLabelId(state.context), | ||
"data-orientation": state.context.orientation, | ||
id: getRootId(scope), | ||
"aria-labelledby": getLabelId(scope), | ||
"data-orientation": prop("orientation"), | ||
"data-disabled": domQuery.dataAttr(groupDisabled), | ||
"aria-orientation": state.context.orientation, | ||
dir: state.context.dir, | ||
"aria-orientation": prop("orientation"), | ||
dir: prop("dir"), | ||
style: { | ||
@@ -133,6 +126,6 @@ position: "relative" | ||
...parts.label.attrs, | ||
dir: state.context.dir, | ||
"data-orientation": state.context.orientation, | ||
dir: prop("dir"), | ||
"data-orientation": prop("orientation"), | ||
"data-disabled": domQuery.dataAttr(groupDisabled), | ||
id: dom.getLabelId(state.context), | ||
id: getLabelId(scope), | ||
onClick: focus | ||
@@ -146,5 +139,5 @@ }); | ||
...parts.item.attrs, | ||
dir: state.context.dir, | ||
id: dom.getItemId(state.context, props2.value), | ||
htmlFor: dom.getItemHiddenInputId(state.context, props2.value), | ||
dir: prop("dir"), | ||
id: getItemId(scope, props2.value), | ||
htmlFor: getItemHiddenInputId(scope, props2.value), | ||
...getItemDataAttrs(props2), | ||
@@ -176,4 +169,4 @@ onPointerMove() { | ||
...parts.itemText.attrs, | ||
dir: state.context.dir, | ||
id: dom.getItemLabelId(state.context, props2.value), | ||
dir: prop("dir"), | ||
id: getItemLabelId(scope, props2.value), | ||
...getItemDataAttrs(props2) | ||
@@ -186,4 +179,4 @@ }); | ||
...parts.itemControl.attrs, | ||
dir: state.context.dir, | ||
id: dom.getItemControlId(state.context, props2.value), | ||
dir: prop("dir"), | ||
id: getItemControlId(scope, props2.value), | ||
"data-active": domQuery.dataAttr(controlState.active), | ||
@@ -197,7 +190,7 @@ "aria-hidden": true, | ||
return normalize.input({ | ||
"data-ownedby": dom.getRootId(state.context), | ||
id: dom.getItemHiddenInputId(state.context, props2.value), | ||
"data-ownedby": getRootId(scope), | ||
id: getItemHiddenInputId(scope, props2.value), | ||
type: "radio", | ||
name: state.context.name || state.context.id, | ||
form: state.context.form, | ||
name: prop("name") || prop("id"), | ||
form: prop("form"), | ||
value: props2.value, | ||
@@ -238,21 +231,22 @@ onClick(event) { | ||
getIndicatorProps() { | ||
const rect = context.get("indicatorRect"); | ||
return normalize.element({ | ||
id: dom.getIndicatorId(state.context), | ||
id: getIndicatorId(scope), | ||
...parts.indicator.attrs, | ||
dir: state.context.dir, | ||
hidden: state.context.value == null, | ||
dir: prop("dir"), | ||
hidden: context.get("value") == null, | ||
"data-disabled": domQuery.dataAttr(groupDisabled), | ||
"data-orientation": state.context.orientation, | ||
"data-orientation": prop("orientation"), | ||
style: { | ||
"--transition-property": "left, top, width, height", | ||
"--left": state.context.indicatorRect?.left, | ||
"--top": state.context.indicatorRect?.top, | ||
"--width": state.context.indicatorRect?.width, | ||
"--height": state.context.indicatorRect?.height, | ||
"--left": rect?.left, | ||
"--top": rect?.top, | ||
"--width": rect?.width, | ||
"--height": rect?.height, | ||
position: "absolute", | ||
willChange: "var(--transition-property)", | ||
transitionProperty: "var(--transition-property)", | ||
transitionDuration: state.context.canIndicatorTransition ? "var(--transition-duration, 150ms)" : "0ms", | ||
transitionDuration: context.get("canIndicatorTransition") ? "var(--transition-duration, 150ms)" : "0ms", | ||
transitionTimingFunction: "var(--transition-timing-function)", | ||
[state.context.orientation === "horizontal" ? "left" : "top"]: state.context.orientation === "horizontal" ? "var(--left)" : "var(--top)" | ||
[prop("orientation") === "horizontal" ? "left" : "top"]: prop("orientation") === "horizontal" ? "var(--left)" : "var(--top)" | ||
} | ||
@@ -263,150 +257,168 @@ }); | ||
} | ||
var { not } = core.guards; | ||
function machine(userContext) { | ||
const ctx = utils.compact(userContext); | ||
return core.createMachine( | ||
{ | ||
id: "radio", | ||
initial: "idle", | ||
context: { | ||
value: null, | ||
activeValue: null, | ||
focusedValue: null, | ||
hoveredValue: null, | ||
disabled: false, | ||
orientation: "vertical", | ||
...ctx, | ||
indicatorRect: {}, | ||
canIndicatorTransition: false, | ||
fieldsetDisabled: false, | ||
focusVisible: false, | ||
ssr: true | ||
var { not } = core.createGuards(); | ||
var machine = core.createMachine({ | ||
props({ props: props2 }) { | ||
return { | ||
orientation: "vertical", | ||
...props2 | ||
}; | ||
}, | ||
initialState() { | ||
return "idle"; | ||
}, | ||
context({ prop, bindable }) { | ||
return { | ||
value: bindable(() => ({ | ||
defaultValue: prop("defaultValue"), | ||
value: prop("value"), | ||
onChange(value) { | ||
prop("onValueChange")?.({ value }); | ||
} | ||
})), | ||
activeValue: bindable(() => ({ | ||
defaultValue: null | ||
})), | ||
focusedValue: bindable(() => ({ | ||
defaultValue: null | ||
})), | ||
hoveredValue: bindable(() => ({ | ||
defaultValue: null | ||
})), | ||
indicatorRect: bindable(() => ({ | ||
defaultValue: {} | ||
})), | ||
canIndicatorTransition: bindable(() => ({ | ||
defaultValue: false | ||
})), | ||
fieldsetDisabled: bindable(() => ({ | ||
defaultValue: false | ||
})), | ||
focusVisible: bindable(() => ({ | ||
defaultValue: false | ||
})), | ||
ssr: bindable(() => ({ | ||
defaultValue: true | ||
})) | ||
}; | ||
}, | ||
refs() { | ||
return { | ||
indicatorCleanup: null | ||
}; | ||
}, | ||
computed: { | ||
isDisabled: ({ prop, context }) => !!prop("disabled") || context.get("fieldsetDisabled") | ||
}, | ||
entry: ["syncIndicatorRect", "syncSsr"], | ||
exit: ["cleanupObserver"], | ||
effects: ["trackFormControlState", "trackFocusVisible"], | ||
watch({ track, action, context }) { | ||
track([() => context.get("value")], () => { | ||
action(["setIndicatorTransition", "syncIndicatorRect", "syncInputElements"]); | ||
}); | ||
}, | ||
on: { | ||
SET_VALUE: [ | ||
{ | ||
guard: not("isTrusted"), | ||
actions: ["setValue", "dispatchChangeEvent"] | ||
}, | ||
computed: { | ||
isDisabled: (ctx2) => !!ctx2.disabled || ctx2.fieldsetDisabled | ||
}, | ||
entry: ["syncIndicatorRect", "syncSsr"], | ||
exit: ["cleanupObserver"], | ||
activities: ["trackFormControlState", "trackFocusVisible"], | ||
watch: { | ||
value: ["setIndicatorTransition", "syncIndicatorRect", "syncInputElements"] | ||
}, | ||
on: { | ||
SET_VALUE: [ | ||
{ | ||
guard: not("isTrusted"), | ||
actions: ["setValue", "dispatchChangeEvent"] | ||
{ | ||
actions: ["setValue"] | ||
} | ||
], | ||
SET_HOVERED: { | ||
actions: ["setHovered"] | ||
}, | ||
SET_ACTIVE: { | ||
actions: ["setActive"] | ||
}, | ||
SET_FOCUSED: { | ||
actions: ["setFocused"] | ||
} | ||
}, | ||
states: { | ||
idle: {} | ||
}, | ||
implementations: { | ||
guards: { | ||
isTrusted: ({ event }) => !!event.isTrusted | ||
}, | ||
effects: { | ||
trackFormControlState({ context, scope }) { | ||
return domQuery.trackFormControl(getRootEl(scope), { | ||
onFieldsetDisabledChange(disabled) { | ||
context.set("fieldsetDisabled", disabled); | ||
}, | ||
{ | ||
actions: ["setValue"] | ||
onFormReset() { | ||
context.set("value", context.initial("value")); | ||
} | ||
], | ||
SET_HOVERED: { | ||
actions: "setHovered" | ||
}, | ||
SET_ACTIVE: { | ||
actions: "setActive" | ||
}, | ||
SET_FOCUSED: { | ||
actions: "setFocused" | ||
} | ||
}); | ||
}, | ||
states: { | ||
idle: {} | ||
trackFocusVisible({ scope }) { | ||
return focusVisible.trackFocusVisible({ root: scope.getRootNode?.() }); | ||
} | ||
}, | ||
{ | ||
guards: { | ||
isTrusted: (_ctx, evt) => !!evt.isTrusted | ||
actions: { | ||
setValue({ context, event }) { | ||
context.set("value", event.value); | ||
}, | ||
activities: { | ||
trackFormControlState(ctx2, _evt, { send, initialContext }) { | ||
return domQuery.trackFormControl(dom.getRootEl(ctx2), { | ||
onFieldsetDisabledChange(disabled) { | ||
ctx2.fieldsetDisabled = disabled; | ||
}, | ||
onFormReset() { | ||
send({ type: "SET_VALUE", value: initialContext.value }); | ||
} | ||
}); | ||
}, | ||
trackFocusVisible(ctx2) { | ||
return focusVisible.trackFocusVisible({ root: dom.getRootNode(ctx2) }); | ||
setHovered({ context, event }) { | ||
context.set("hoveredValue", event.value); | ||
}, | ||
setActive({ context, event }) { | ||
context.set("activeValue", event.value); | ||
}, | ||
setFocused({ context, event }) { | ||
context.set("focusedValue", event.value); | ||
context.set("focusVisible", event.focusVisible); | ||
}, | ||
syncInputElements({ context, scope }) { | ||
const inputs = getInputEls(scope); | ||
inputs.forEach((input) => { | ||
input.checked = input.value === context.get("value"); | ||
}); | ||
}, | ||
setIndicatorTransition({ context }) { | ||
context.set("canIndicatorTransition", utils.isString(context.get("value"))); | ||
}, | ||
cleanupObserver({ refs }) { | ||
refs.get("indicatorCleanup")?.(); | ||
}, | ||
syncSsr({ context }) { | ||
context.set("ssr", false); | ||
}, | ||
syncIndicatorRect({ context, scope, refs }) { | ||
refs.get("indicatorCleanup")?.(); | ||
if (!getIndicatorEl(scope)) return; | ||
const value = context.get("value"); | ||
const radioEl = getRadioEl(scope, value); | ||
if (value == null || !radioEl) { | ||
context.set("indicatorRect", {}); | ||
return; | ||
} | ||
const indicatorCleanup = elementRect.trackElementRect(radioEl, { | ||
getRect(el) { | ||
return getOffsetRect(el); | ||
}, | ||
onChange(rect) { | ||
context.set("indicatorRect", resolveRect(rect)); | ||
domQuery.nextTick(() => { | ||
context.set("canIndicatorTransition", false); | ||
}); | ||
} | ||
}); | ||
refs.set("indicatorCleanup", indicatorCleanup); | ||
}, | ||
actions: { | ||
setValue(ctx2, evt) { | ||
set.value(ctx2, evt.value); | ||
}, | ||
setHovered(ctx2, evt) { | ||
ctx2.hoveredValue = evt.value; | ||
}, | ||
setActive(ctx2, evt) { | ||
ctx2.activeValue = evt.value; | ||
}, | ||
setFocused(ctx2, evt) { | ||
ctx2.focusedValue = evt.value; | ||
ctx2.focusVisible = evt.focusVisible; | ||
}, | ||
syncInputElements(ctx2) { | ||
const inputs = dom.getInputEls(ctx2); | ||
inputs.forEach((input) => { | ||
input.checked = input.value === ctx2.value; | ||
}); | ||
}, | ||
setIndicatorTransition(ctx2) { | ||
ctx2.canIndicatorTransition = utils.isString(ctx2.value); | ||
}, | ||
cleanupObserver(ctx2) { | ||
ctx2.indicatorCleanup?.(); | ||
}, | ||
syncSsr(ctx2) { | ||
ctx2.ssr = false; | ||
}, | ||
syncIndicatorRect(ctx2) { | ||
ctx2.indicatorCleanup?.(); | ||
if (!dom.getIndicatorEl(ctx2)) return; | ||
const value = ctx2.value; | ||
const radioEl = dom.getActiveRadioEl(ctx2); | ||
if (value == null || !radioEl) { | ||
ctx2.indicatorRect = {}; | ||
return; | ||
} | ||
ctx2.indicatorCleanup = elementRect.trackElementRect(radioEl, { | ||
getRect(el) { | ||
return dom.getOffsetRect(el); | ||
}, | ||
onChange(rect) { | ||
ctx2.indicatorRect = dom.resolveRect(rect); | ||
domQuery.nextTick(() => { | ||
ctx2.canIndicatorTransition = false; | ||
}); | ||
} | ||
}); | ||
}, | ||
dispatchChangeEvent(ctx2) { | ||
const inputEls = dom.getInputEls(ctx2); | ||
inputEls.forEach((inputEl) => { | ||
const checked = inputEl.value === ctx2.value; | ||
if (checked === inputEl.checked) return; | ||
domQuery.dispatchInputCheckedEvent(inputEl, { checked }); | ||
}); | ||
} | ||
dispatchChangeEvent({ context, scope }) { | ||
const inputEls = getInputEls(scope); | ||
inputEls.forEach((inputEl) => { | ||
const checked = inputEl.value === context.get("value"); | ||
if (checked === inputEl.checked) return; | ||
domQuery.dispatchInputCheckedEvent(inputEl, { checked }); | ||
}); | ||
} | ||
} | ||
); | ||
} | ||
var invoke = { | ||
change: (ctx) => { | ||
if (ctx.value == null) return; | ||
ctx.onValueChange?.({ value: ctx.value }); | ||
} | ||
}; | ||
var set = { | ||
value: (ctx, value) => { | ||
if (utils.isEqual(ctx.value, value)) return; | ||
ctx.value = value; | ||
invoke.change(ctx); | ||
} | ||
}; | ||
}); | ||
var props = types.createProps()([ | ||
@@ -423,3 +435,4 @@ "dir", | ||
"readOnly", | ||
"value" | ||
"value", | ||
"defaultValue" | ||
]); | ||
@@ -426,0 +439,0 @@ var splitProps = utils.createSplitProps(props); |
{ | ||
"name": "@zag-js/radio-group", | ||
"version": "0.82.2", | ||
"version": "1.0.0", | ||
"description": "Core logic for the radio group widget implemented as a state machine", | ||
@@ -30,9 +30,9 @@ "keywords": [ | ||
"dependencies": { | ||
"@zag-js/anatomy": "0.82.2", | ||
"@zag-js/dom-query": "0.82.2", | ||
"@zag-js/element-rect": "0.82.2", | ||
"@zag-js/focus-visible": "0.82.2", | ||
"@zag-js/utils": "0.82.2", | ||
"@zag-js/core": "0.82.2", | ||
"@zag-js/types": "0.82.2" | ||
"@zag-js/anatomy": "1.0.0", | ||
"@zag-js/dom-query": "1.0.0", | ||
"@zag-js/element-rect": "1.0.0", | ||
"@zag-js/utils": "1.0.0", | ||
"@zag-js/focus-visible": "1.0.0", | ||
"@zag-js/core": "1.0.0", | ||
"@zag-js/types": "1.0.0" | ||
}, | ||
@@ -48,5 +48,10 @@ "devDependencies": { | ||
".": { | ||
"types": "./dist/index.d.ts", | ||
"import": "./dist/index.mjs", | ||
"require": "./dist/index.js" | ||
"import": { | ||
"types": "./dist/index.d.mts", | ||
"default": "./dist/index.mjs" | ||
}, | ||
"require": { | ||
"types": "./dist/index.d.ts", | ||
"default": "./dist/index.js" | ||
} | ||
}, | ||
@@ -53,0 +58,0 @@ "./package.json": "./package.json" |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
42371
4.39%1046
8.39%0
-100%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated
Updated
Updated
Updated
Updated
Updated
Updated