diff --git a/.changeset/cyan-parrots-grin.md b/.changeset/cyan-parrots-grin.md new file mode 100644 index 0000000000..ca2674ac68 --- /dev/null +++ b/.changeset/cyan-parrots-grin.md @@ -0,0 +1,10 @@ +--- +"@zag-js/checkbox": minor +--- + +Rename `api` properties + +- `isChecked` to `checked` +- `isDisabled` to `disabled` +- `isIndeterminate` to `indeterminate` +- `isFocused` to `focused` diff --git a/.changeset/friendly-rings-impress.md b/.changeset/friendly-rings-impress.md new file mode 100644 index 0000000000..38784828c0 --- /dev/null +++ b/.changeset/friendly-rings-impress.md @@ -0,0 +1,6 @@ +--- +"@zag-js/avatar": minor +--- + +- Rename `api.isLoaded` to `api.loaded` +- Remove `api.showFallback` since it's equivalent to `!api.loaded` diff --git a/.changeset/gold-pigs-smash.md b/.changeset/gold-pigs-smash.md new file mode 100644 index 0000000000..6b0ca3cccb --- /dev/null +++ b/.changeset/gold-pigs-smash.md @@ -0,0 +1,7 @@ +--- +"@zag-js/radio-group": minor +"@zag-js/checkbox": minor +"@zag-js/switch": minor +--- + +Add support for `readOnly` prop diff --git a/.changeset/large-weeks-shout.md b/.changeset/large-weeks-shout.md new file mode 100644 index 0000000000..1d6bee5450 --- /dev/null +++ b/.changeset/large-weeks-shout.md @@ -0,0 +1,8 @@ +--- +"@zag-js/editable": minor +--- + +Rename `api` properties + +- `isEditing` -> `editing` +- `isValueEmpty` -> `empty` diff --git a/.changeset/plenty-cherries-lay.md b/.changeset/plenty-cherries-lay.md new file mode 100644 index 0000000000..c7c262201c --- /dev/null +++ b/.changeset/plenty-cherries-lay.md @@ -0,0 +1,13 @@ +--- +"@zag-js/tree-view": minor +--- + +- Rename `api.getItemState` properties + + - `isDisabled` -> `disabled` + - `isFocused` -> `focused` + - `isSelected` -> `selected` + +- Rename `api.getBranchState` properties + + - `isExpanded` -> `expanded` diff --git a/.changeset/polite-vans-nail.md b/.changeset/polite-vans-nail.md new file mode 100644 index 0000000000..62fbb45405 --- /dev/null +++ b/.changeset/polite-vans-nail.md @@ -0,0 +1,10 @@ +--- +"@zag-js/combobox": minor +--- + +Rename `api` properties + +- `isFocused` -> `focused` +- `isOpen` -> `open` +- `isInputValueEmpty` -> `inputEmpty` +- `open()`, `close()` -> `setOpen(true|false)` diff --git a/.changeset/quick-flowers-sparkle.md b/.changeset/quick-flowers-sparkle.md new file mode 100644 index 0000000000..90dd3a247e --- /dev/null +++ b/.changeset/quick-flowers-sparkle.md @@ -0,0 +1,8 @@ +--- +"@zag-js/signature-pad": minor +--- + +Rename `api` properties + +- `isDrawing` -> `drawing` +- `isEmpty` -> `empty` diff --git a/.changeset/real-icons-study.md b/.changeset/real-icons-study.md new file mode 100644 index 0000000000..4d40cc0f28 --- /dev/null +++ b/.changeset/real-icons-study.md @@ -0,0 +1,10 @@ +--- +"@zag-js/collapsible": minor +--- + +Rename `api` properties + +- `isVisible` -> `visible` +- `isDisabled` -> `disabled` +- `isOpen` -> `open` +- `open`, `close` -> `setOpen(true|false)` diff --git a/.changeset/sour-boxes-march.md b/.changeset/sour-boxes-march.md new file mode 100644 index 0000000000..156a0b7ff6 --- /dev/null +++ b/.changeset/sour-boxes-march.md @@ -0,0 +1,9 @@ +--- +"@zag-js/file-upload": minor +--- + +Rename `api` properties + +- `isDragging` -> `dragging` +- `isFocused` -> `focused` +- `open()` -> `openFilePicker()` diff --git a/.changeset/swift-hornets-hug.md b/.changeset/swift-hornets-hug.md new file mode 100644 index 0000000000..db776ab2e9 --- /dev/null +++ b/.changeset/swift-hornets-hug.md @@ -0,0 +1,12 @@ +--- +"@zag-js/carousel": minor +--- + +- Rename `api.getItemState` properties + + - `isCurrent` to `current` + - `isNext` to `next` + - `isPrevious` to `previous` + - `isInView` to `inView` + +- Rename `api.isAutoPlay` to `api.autoPlaying` diff --git a/.changeset/swift-years-do.md b/.changeset/swift-years-do.md new file mode 100644 index 0000000000..b9cf3b7e8a --- /dev/null +++ b/.changeset/swift-years-do.md @@ -0,0 +1,9 @@ +--- +"@zag-js/color-picker": minor +--- + +Rename `api` properties + +- `isDragging` -> `dragging` +- `isOpen` -> `open` +- `open()`, `close()` -> `setOpen(true|false)` diff --git a/.changeset/three-planes-mix.md b/.changeset/three-planes-mix.md new file mode 100644 index 0000000000..b417e631fe --- /dev/null +++ b/.changeset/three-planes-mix.md @@ -0,0 +1,5 @@ +--- +"@zag-js/clipboard": minor +--- + +Rename `api.isCopied` to `api.copied` diff --git a/.changeset/unlucky-pumpkins-impress.md b/.changeset/unlucky-pumpkins-impress.md new file mode 100644 index 0000000000..36643677f3 --- /dev/null +++ b/.changeset/unlucky-pumpkins-impress.md @@ -0,0 +1,9 @@ +--- +"@zag-js/tabs": minor +--- + +Rename `api.getTriggerState` properties + +- `isSelected` -> `selected` +- `isDisabled` -> `disabled` +- `isFocused` -> `focused` diff --git a/.changeset/witty-tomatoes-roll.md b/.changeset/witty-tomatoes-roll.md new file mode 100644 index 0000000000..15735e1686 --- /dev/null +++ b/.changeset/witty-tomatoes-roll.md @@ -0,0 +1,8 @@ +--- +"@zag-js/accordion": minor +--- + +- Rename `getItemState` properties + - `isOpen` -> `expanded` + - `isDisabled` -> `disabled` + - `isFocused` -> `focused` diff --git a/.xstate/toggle-group.js b/.xstate/toggle-group.js index 74fae65531..52b2b1b8cb 100644 --- a/.xstate/toggle-group.js +++ b/.xstate/toggle-group.js @@ -15,7 +15,7 @@ const fetchMachine = createMachine({ context: { "!(isClickFocus && isTabbingBackward)": false }, - entry: ["checkFocusableToggles", "checkIfWithinToolbar"], + entry: ["checkIfWithinToolbar"], on: { "VALUE.SET": { actions: ["setValue"] diff --git a/examples/next-ts/components/dialog.tsx b/examples/next-ts/components/dialog.tsx index 2f901d4d3b..7737ff8642 100644 --- a/examples/next-ts/components/dialog.tsx +++ b/examples/next-ts/components/dialog.tsx @@ -28,7 +28,7 @@ export function Dialog(props: Props) { return ( <> Open Dialog - {api.isOpen && ( + {api.open && ( diff --git a/examples/next-ts/package.json b/examples/next-ts/package.json index 5e8a1d5856..a8884cd3e1 100644 --- a/examples/next-ts/package.json +++ b/examples/next-ts/package.json @@ -80,7 +80,6 @@ "@zag-js/tree-view": "workspace:*", "@zag-js/types": "workspace:*", "@zag-js/utils": "workspace:*", - "@zag-js/visually-hidden": "workspace:*", "form-serialize": "0.7.2", "lucide-react": "0.372.0", "match-sorter": "6.3.4", diff --git a/examples/next-ts/pages/checkbox.tsx b/examples/next-ts/pages/checkbox.tsx index 98a3ebcc2c..b3ab9f27bc 100644 --- a/examples/next-ts/pages/checkbox.tsx +++ b/examples/next-ts/pages/checkbox.tsx @@ -34,15 +34,15 @@ export default function Page() { - Input {api.isChecked ? "Checked" : "Unchecked"} + Input {api.checked ? "Checked" : "Unchecked"} Indicator - api.setChecked(true)}> + api.setChecked(true)}> Check - api.setChecked(false)}> + api.setChecked(false)}> Uncheck Reset Form diff --git a/examples/next-ts/pages/clipboard.tsx b/examples/next-ts/pages/clipboard.tsx index dedfbe3436..378716fbe1 100644 --- a/examples/next-ts/pages/clipboard.tsx +++ b/examples/next-ts/pages/clipboard.tsx @@ -29,7 +29,7 @@ export default function Page() { Copy this link - {api.isCopied ? : } + {api.copied ? : } Copied! Copy diff --git a/examples/next-ts/pages/cmdk.tsx b/examples/next-ts/pages/cmdk.tsx index d932cddd43..a722e48a08 100644 --- a/examples/next-ts/pages/cmdk.tsx +++ b/examples/next-ts/pages/cmdk.tsx @@ -102,14 +102,14 @@ export default function Page() { useEffect(() => { const fn = (event: KeyboardEvent) => { - if (dialogApi.isOpen) return + if (dialogApi.open) return const isMac = /(Mac|iPhone|iPod|iPad)/i.test(navigator?.platform) const hotkey = isMac ? "metaKey" : "ctrlKey" if (event.key?.toLowerCase() === "k" && event[hotkey]) { event.preventDefault() - dialogApi.open() + dialogApi.setOpen(true) } } document.addEventListener("keydown", fn, true) @@ -129,7 +129,7 @@ export default function Page() { or press Cmd+K - {dialogApi.isOpen && ( + {dialogApi.open && ( @@ -139,7 +139,7 @@ export default function Page() { collection={collection} onValueChange={({ value }) => { console.log("Selected value:", value) - queueMicrotask(() => dialogApi.close()) + queueMicrotask(() => dialogApi.setOpen(false)) }} onInputValueChange={({ inputValue }) => { setInputValue(inputValue) diff --git a/examples/next-ts/pages/collapsible.tsx b/examples/next-ts/pages/collapsible.tsx index 427f08268a..a8fef6bc7d 100644 --- a/examples/next-ts/pages/collapsible.tsx +++ b/examples/next-ts/pages/collapsible.tsx @@ -38,8 +38,8 @@ export default function Page() { Toggle Controls - Open - Close + api.setOpen(true)}>Open + api.setOpen(false)}>Close diff --git a/examples/next-ts/pages/combo-textarea.tsx b/examples/next-ts/pages/combo-textarea.tsx index 0b75de6509..f553141110 100644 --- a/examples/next-ts/pages/combo-textarea.tsx +++ b/examples/next-ts/pages/combo-textarea.tsx @@ -96,11 +96,11 @@ export default function Page() { api.reposition() }, onPointerDown() { - api.close() + api.setOpen(true) }, onKeyDown(event) { if (event.key === "ArrowLeft" || event.key === "ArrowRight") { - api.close() + api.setOpen(false) } }, onChange(event) { @@ -108,9 +108,9 @@ export default function Page() { const searchValue = getSearchValue(event.currentTarget) if (trigger) { - api.open() + api.setOpen(true) } else if (!searchValue) { - api.close() + api.setOpen(false) } setSearchValue(searchValue) diff --git a/examples/next-ts/pages/dialog/controlled.tsx b/examples/next-ts/pages/dialog/controlled.tsx index c8ee5b1165..62288e3ea1 100644 --- a/examples/next-ts/pages/dialog/controlled.tsx +++ b/examples/next-ts/pages/dialog/controlled.tsx @@ -23,8 +23,8 @@ export default function Dialog() { setOpen(!isOpen)}>Open Dialog state - isOpen: {String(isOpen)} - machine - isOpen: {String(api.isOpen)} - {api.isOpen && ( + machine - isOpen: {String(api.open)} + {api.open && ( diff --git a/examples/next-ts/pages/dialog/index.tsx b/examples/next-ts/pages/dialog/index.tsx index 039ef61584..e7eb2dda01 100644 --- a/examples/next-ts/pages/dialog/index.tsx +++ b/examples/next-ts/pages/dialog/index.tsx @@ -33,7 +33,7 @@ export default function Page() { - {parentDialog.isOpen && ( + {parentDialog.open && ( @@ -52,7 +52,7 @@ export default function Page() { Open Nested - {childDialog.isOpen && ( + {childDialog.open && ( @@ -61,7 +61,7 @@ export default function Page() { X - parentDialog.close()} data-testid="special-close"> + parentDialog.setOpen(false)} data-testid="special-close"> Close Dialog 1 diff --git a/examples/next-ts/pages/dialog/overflow.tsx b/examples/next-ts/pages/dialog/overflow.tsx index cc5abee65f..a190b77b3b 100644 --- a/examples/next-ts/pages/dialog/overflow.tsx +++ b/examples/next-ts/pages/dialog/overflow.tsx @@ -9,7 +9,7 @@ export default function Dialog() { Click me - {api.isOpen && ( + {api.open && ( diff --git a/examples/next-ts/pages/editable.tsx b/examples/next-ts/pages/editable.tsx index d5649ac6e1..6910ba55ab 100644 --- a/examples/next-ts/pages/editable.tsx +++ b/examples/next-ts/pages/editable.tsx @@ -29,12 +29,12 @@ export default function Page() { - {!api.isEditing && ( + {!api.editing && ( Edit )} - {api.isEditing && ( + {api.editing && ( <> Save diff --git a/examples/next-ts/pages/hover-card.tsx b/examples/next-ts/pages/hover-card.tsx index f73edac1ac..84c79c895f 100644 --- a/examples/next-ts/pages/hover-card.tsx +++ b/examples/next-ts/pages/hover-card.tsx @@ -29,7 +29,7 @@ export default function Page() { Twitter - {api.isOpen && ( + {api.open && ( diff --git a/examples/next-ts/pages/pagination.tsx b/examples/next-ts/pages/pagination.tsx index 4a9aa2c29d..41dce6dfb0 100644 --- a/examples/next-ts/pages/pagination.tsx +++ b/examples/next-ts/pages/pagination.tsx @@ -1,7 +1,6 @@ import * as pagination from "@zag-js/pagination" import { normalizeProps, useMachine } from "@zag-js/react" import { paginationControls, paginationData } from "@zag-js/shared" -import { visuallyHiddenStyle } from "@zag-js/visually-hidden" import { useId, useState } from "react" import { Print } from "../components/print" import { StateVisualizer } from "../components/state-visualizer" @@ -60,9 +59,7 @@ export default function Page() { - - Previous Page - + Previous {api.pages.map((page, i) => { if (page.type === "page") @@ -81,9 +78,7 @@ export default function Page() { ) })} - - Next Page - + Next diff --git a/examples/next-ts/pages/popover-selection.tsx b/examples/next-ts/pages/popover-selection.tsx index c3474551ed..0836824052 100644 --- a/examples/next-ts/pages/popover-selection.tsx +++ b/examples/next-ts/pages/popover-selection.tsx @@ -53,14 +53,14 @@ export default function Page() { const onMouseUp = () => { if (!hasSelectionWithin(node)) return api.reposition() - api.open() + api.setOpen(true) } const onSelect = () => { if (hasSelectionWithin(node)) { return api.reposition() } - api.close() + api.setOpen(false) } doc.addEventListener("mouseup", onMouseUp) diff --git a/examples/next-ts/pages/presence.tsx b/examples/next-ts/pages/presence.tsx index 96c19a5128..2bb4098289 100644 --- a/examples/next-ts/pages/presence.tsx +++ b/examples/next-ts/pages/presence.tsx @@ -17,7 +17,7 @@ export default function Page() { return ( setPresent((c) => !c)}>Toggle - {api.isPresent && ( + {api.present && ( { api.setNode(node) diff --git a/examples/next-ts/pages/radio-group.tsx b/examples/next-ts/pages/radio-group.tsx index 4f7997bd5e..0e88d6532d 100644 --- a/examples/next-ts/pages/radio-group.tsx +++ b/examples/next-ts/pages/radio-group.tsx @@ -10,9 +10,15 @@ import { useControls } from "../hooks/use-controls" export default function Page() { const controls = useControls(radioControls) - const [state, send] = useMachine(radio.machine({ id: useId(), name: "fruit" }), { - context: controls.context, - }) + const [state, send] = useMachine( + radio.machine({ + id: useId(), + name: "fruit", + }), + { + context: controls.context, + }, + ) const api = radio.connect(state, send, normalizeProps) diff --git a/examples/next-ts/pages/rating-group.tsx b/examples/next-ts/pages/rating-group.tsx index 18cfc53666..b1b01daf3a 100644 --- a/examples/next-ts/pages/rating-group.tsx +++ b/examples/next-ts/pages/rating-group.tsx @@ -62,7 +62,7 @@ export default function Page() { const state = api.getItemState({ index }) return ( - {state.isHalf ? : } + {state.half ? : } ) })} diff --git a/examples/next-ts/pages/select-in-dialog.tsx b/examples/next-ts/pages/select-in-dialog.tsx index 409420b5bf..064bd29601 100644 --- a/examples/next-ts/pages/select-in-dialog.tsx +++ b/examples/next-ts/pages/select-in-dialog.tsx @@ -47,7 +47,7 @@ export default function Page() { Open Dialog - {api.isOpen && ( + {api.open && ( diff --git a/examples/next-ts/pages/select.tsx b/examples/next-ts/pages/select.tsx index 8d4d3bee50..cee9d5e76f 100644 --- a/examples/next-ts/pages/select.tsx +++ b/examples/next-ts/pages/select.tsx @@ -54,7 +54,7 @@ export default function Page() { > {/* Hidden select */} - {api.isValueEmpty && } + {api.empty && } {selectData.map((option) => ( {option.label} diff --git a/examples/next-ts/pages/switch.tsx b/examples/next-ts/pages/switch.tsx index 5f9da9b0ca..fd36d38a80 100644 --- a/examples/next-ts/pages/switch.tsx +++ b/examples/next-ts/pages/switch.tsx @@ -29,7 +29,7 @@ export default function Page() { - Feature is {api.isChecked ? "enabled" : "disabled"} + Feature is {api.checked ? "enabled" : "disabled"} diff --git a/examples/next-ts/pages/toast.tsx b/examples/next-ts/pages/toast.tsx index c9b12c85dc..b02e172c00 100644 --- a/examples/next-ts/pages/toast.tsx +++ b/examples/next-ts/pages/toast.tsx @@ -13,23 +13,10 @@ function ToastItem({ actor }: { actor: toast.Service }) { const [state, send] = useActor(actor) const api = toast.connect(state, send, normalizeProps) - const progressbarProps = { - "data-scope": "toast", - "data-part": "progressbar", - "data-type": state.context.type, - style: { - opacity: api.isVisible ? 1 : 0, - transformOrigin: api.isRtl ? "right" : "left", - animationName: api.type === "loading" ? "none" : undefined, - animationPlayState: api.isPaused ? "paused" : "running", - animationDuration: "var(--duration)", - }, - } - return ( - + - + {api.type === "loading" && } {api.title} @@ -39,7 +26,7 @@ function ToastItem({ actor }: { actor: toast.Service }) { - + ) } diff --git a/examples/next-ts/pages/tooltip.tsx b/examples/next-ts/pages/tooltip.tsx index 441ca0116b..64c7a9ba68 100644 --- a/examples/next-ts/pages/tooltip.tsx +++ b/examples/next-ts/pages/tooltip.tsx @@ -27,7 +27,7 @@ export default function Page() { Hover me - {api.isOpen && ( + {api.open && ( Tooltip @@ -38,7 +38,7 @@ export default function Page() { Over me - {api2.isOpen && ( + {api2.open && ( diff --git a/examples/nuxt-ts/package.json b/examples/nuxt-ts/package.json index 499eb489da..24c3592cd7 100644 --- a/examples/nuxt-ts/package.json +++ b/examples/nuxt-ts/package.json @@ -77,7 +77,6 @@ "@zag-js/tree-view": "workspace:*", "@zag-js/types": "workspace:*", "@zag-js/utils": "workspace:*", - "@zag-js/visually-hidden": "workspace:*", "@zag-js/vue": "workspace:*", "epic-spinners": "2.0.0", "form-serialize": "0.7.2", diff --git a/examples/nuxt-ts/pages/checkbox.vue b/examples/nuxt-ts/pages/checkbox.vue index 1f8341a947..b67cb3f00c 100644 --- a/examples/nuxt-ts/pages/checkbox.vue +++ b/examples/nuxt-ts/pages/checkbox.vue @@ -30,13 +30,13 @@ const api = computed(() => checkbox.connect(state.value, send, normalizeProps)) - Input {{ api.isChecked ? "Checked" : "Unchecked" }} + Input {{ api.checked ? "Checked" : "Unchecked" }} Indicator - api.setChecked(true)">Check - api.setChecked(false)">Uncheck + api.setChecked(true)">Check + api.setChecked(false)">Uncheck Reset Form diff --git a/examples/nuxt-ts/pages/clipboard.vue b/examples/nuxt-ts/pages/clipboard.vue index 8a68784370..d84b3a2a02 100644 --- a/examples/nuxt-ts/pages/clipboard.vue +++ b/examples/nuxt-ts/pages/clipboard.vue @@ -26,7 +26,7 @@ const api = computed(() => clipboard.connect(state.value, send, normalizeProps)) - + diff --git a/examples/nuxt-ts/pages/editable.vue b/examples/nuxt-ts/pages/editable.vue index 3fca9482d5..b6824225a5 100644 --- a/examples/nuxt-ts/pages/editable.vue +++ b/examples/nuxt-ts/pages/editable.vue @@ -20,9 +20,9 @@ const api = computed(() => editable.connect(state.value, send, normalizeProps)) - Edit + Edit - + Save Cancel diff --git a/examples/nuxt-ts/pages/hover-card.vue b/examples/nuxt-ts/pages/hover-card.vue index 03870049a8..d51305275a 100644 --- a/examples/nuxt-ts/pages/hover-card.vue +++ b/examples/nuxt-ts/pages/hover-card.vue @@ -17,7 +17,7 @@ const api = computed(() => hoverCard.connect(state.value, send, normalizeProps)) Twitter - + diff --git a/examples/nuxt-ts/pages/rating-group.vue b/examples/nuxt-ts/pages/rating-group.vue index cd46775e18..e4d3e8a90b 100644 --- a/examples/nuxt-ts/pages/rating-group.vue +++ b/examples/nuxt-ts/pages/rating-group.vue @@ -27,7 +27,7 @@ const items = computed(() => - + diff --git a/examples/nuxt-ts/pages/switch.vue b/examples/nuxt-ts/pages/switch.vue index 14c1c33423..a81ca014ac 100644 --- a/examples/nuxt-ts/pages/switch.vue +++ b/examples/nuxt-ts/pages/switch.vue @@ -23,7 +23,7 @@ const api = computed(() => zagSwitch.connect(state.value, send, normalizeProps)) - Feature is {{ api.isChecked ? "enabled" : "disabled" }} + Feature is {{ api.checked ? "enabled" : "disabled" }} diff --git a/examples/nuxt-ts/pages/tooltip.vue b/examples/nuxt-ts/pages/tooltip.vue index 1d4ac7d911..d11ce05f63 100644 --- a/examples/nuxt-ts/pages/tooltip.vue +++ b/examples/nuxt-ts/pages/tooltip.vue @@ -20,7 +20,7 @@ const api = computed(() => tooltip.connect(state.value, send, normalizeProps)) {{ state.value }} Hover me - + Tooltip with alot of text probably diff --git a/examples/preact-ts/package.json b/examples/preact-ts/package.json index 74ee7e4067..c58058d4dc 100644 --- a/examples/preact-ts/package.json +++ b/examples/preact-ts/package.json @@ -77,7 +77,6 @@ "@zag-js/tree-view": "workspace:*", "@zag-js/types": "workspace:*", "@zag-js/utils": "workspace:*", - "@zag-js/visually-hidden": "workspace:*", "match-sorter": "6.3.4", "lucide-preact": "0.372.0", "preact": "10.20.2", diff --git a/examples/solid-ts/package.json b/examples/solid-ts/package.json index e20b5f446d..b8dec359e9 100644 --- a/examples/solid-ts/package.json +++ b/examples/solid-ts/package.json @@ -87,7 +87,6 @@ "@zag-js/tree-view": "workspace:*", "@zag-js/types": "workspace:*", "@zag-js/utils": "workspace:*", - "@zag-js/visually-hidden": "workspace:*", "form-serialize": "0.7.2", "match-sorter": "6.3.4", "lucide-solid": "0.372.0", diff --git a/examples/solid-ts/src/pages/checkbox.tsx b/examples/solid-ts/src/pages/checkbox.tsx index 89e205fac4..52b1a539d9 100644 --- a/examples/solid-ts/src/pages/checkbox.tsx +++ b/examples/solid-ts/src/pages/checkbox.tsx @@ -35,17 +35,17 @@ export default function Page() { - Input {api().isChecked ? "Checked" : "Unchecked"} + Input {api().checked ? "Checked" : "Unchecked"} Indicator - api().setChecked(true)}> + api().setChecked(true)}> Check - api().setChecked(false)}> + api().setChecked(false)}> Uncheck Reset Form diff --git a/examples/solid-ts/src/pages/clipboard.tsx b/examples/solid-ts/src/pages/clipboard.tsx index 6279f4080e..7f46fc1766 100644 --- a/examples/solid-ts/src/pages/clipboard.tsx +++ b/examples/solid-ts/src/pages/clipboard.tsx @@ -30,7 +30,7 @@ export default function Page() { - }> + }> diff --git a/examples/solid-ts/src/pages/collapsible.tsx b/examples/solid-ts/src/pages/collapsible.tsx index cd26e4a204..a6b8adf341 100644 --- a/examples/solid-ts/src/pages/collapsible.tsx +++ b/examples/solid-ts/src/pages/collapsible.tsx @@ -33,8 +33,8 @@ export default function Page() { Toggle Controls - Open - Close + api().setOpen(true)}>Open + api().setOpen(false)}>Close diff --git a/examples/solid-ts/src/pages/date-picker.tsx b/examples/solid-ts/src/pages/date-picker.tsx index 6bb25adf4d..0dc42a186a 100644 --- a/examples/solid-ts/src/pages/date-picker.tsx +++ b/examples/solid-ts/src/pages/date-picker.tsx @@ -36,7 +36,7 @@ export default function Page() { - + ❌ 🗓 diff --git a/examples/solid-ts/src/pages/dialog.tsx b/examples/solid-ts/src/pages/dialog.tsx index f8ccc9ff2a..486053199e 100644 --- a/examples/solid-ts/src/pages/dialog.tsx +++ b/examples/solid-ts/src/pages/dialog.tsx @@ -25,7 +25,7 @@ export default function Page() { - + @@ -43,7 +43,7 @@ export default function Page() { Open Nested - + @@ -52,7 +52,7 @@ export default function Page() { X - parentDialog().close()} data-testid="special-close"> + parentDialog().setOpen(false)} data-testid="special-close"> Close Dialog 1 diff --git a/examples/solid-ts/src/pages/editable.tsx b/examples/solid-ts/src/pages/editable.tsx index d30b5ed4b6..7418ede7f6 100644 --- a/examples/solid-ts/src/pages/editable.tsx +++ b/examples/solid-ts/src/pages/editable.tsx @@ -28,12 +28,12 @@ export default function Page() { - + Edit - + <> Save diff --git a/examples/solid-ts/src/pages/hover-card.tsx b/examples/solid-ts/src/pages/hover-card.tsx index da62de760a..586daf5e48 100644 --- a/examples/solid-ts/src/pages/hover-card.tsx +++ b/examples/solid-ts/src/pages/hover-card.tsx @@ -23,7 +23,7 @@ export default function Page() { Twitter - + diff --git a/examples/solid-ts/src/pages/pagination.tsx b/examples/solid-ts/src/pages/pagination.tsx index 77610419fa..a2f9ef800d 100644 --- a/examples/solid-ts/src/pages/pagination.tsx +++ b/examples/solid-ts/src/pages/pagination.tsx @@ -1,6 +1,5 @@ import * as pagination from "@zag-js/pagination" import { normalizeProps, useMachine } from "@zag-js/solid" -import { visuallyHiddenStyle } from "@zag-js/visually-hidden" import { createMemo, createUniqueId, For } from "solid-js" import { paginationControls, paginationData } from "@zag-js/shared" import { StateVisualizer } from "../components/state-visualizer" @@ -56,9 +55,7 @@ export default function Page() { - - Previous Page - + Previous {(page, i) => { @@ -78,9 +75,7 @@ export default function Page() { }} - - Next Page - + Next diff --git a/examples/solid-ts/src/pages/presence.tsx b/examples/solid-ts/src/pages/presence.tsx index 7223fa53c9..77083b20f3 100644 --- a/examples/solid-ts/src/pages/presence.tsx +++ b/examples/solid-ts/src/pages/presence.tsx @@ -16,7 +16,7 @@ export default function Page() { return ( setPresent((c) => !c)}>Toggle - + { api().setNode(node) diff --git a/examples/solid-ts/src/pages/rating-group.tsx b/examples/solid-ts/src/pages/rating-group.tsx index 5f7ab5029c..e3646662a5 100644 --- a/examples/solid-ts/src/pages/rating-group.tsx +++ b/examples/solid-ts/src/pages/rating-group.tsx @@ -62,7 +62,7 @@ export default function Page() { {(index) => { const state = createMemo(() => api().getItemState({ index: index() })) return ( - {state().isHalf ? : } + {state().half ? : } ) }} diff --git a/examples/solid-ts/src/pages/switch.tsx b/examples/solid-ts/src/pages/switch.tsx index f6310021c9..7891ac5367 100644 --- a/examples/solid-ts/src/pages/switch.tsx +++ b/examples/solid-ts/src/pages/switch.tsx @@ -29,7 +29,7 @@ export default function Page() { - Feature is {api().isChecked ? "enabled" : "disabled"} + Feature is {api().checked ? "enabled" : "disabled"} diff --git a/examples/solid-ts/src/pages/toast.tsx b/examples/solid-ts/src/pages/toast.tsx index 35ab01dfe1..784cacd03f 100644 --- a/examples/solid-ts/src/pages/toast.tsx +++ b/examples/solid-ts/src/pages/toast.tsx @@ -12,23 +12,10 @@ function ToastItem(props: { actor: toast.Service }) { const [state, send] = useActor(props.actor) const api = createMemo(() => toast.connect(state, send, normalizeProps)) - const progressbarProps = createMemo(() => ({ - "data-scope": "toast", - "data-part": "progressbar", - "data-type": state.context.type, - style: { - opacity: api().isVisible ? 1 : 0, - "transform-origin": api().isRtl ? "right" : "left", - "animation-name": api().type === "loading" ? "none" : undefined, - "animation-play-state": api().isPaused ? "paused" : "running", - "animation-duration": `${state.context.duration}ms`, - }, - })) - return ( - + {api().type === "loading" && } {api().title} diff --git a/examples/solid-ts/src/pages/tooltip.tsx b/examples/solid-ts/src/pages/tooltip.tsx index cf003e2a6c..2d1c53080e 100644 --- a/examples/solid-ts/src/pages/tooltip.tsx +++ b/examples/solid-ts/src/pages/tooltip.tsx @@ -20,7 +20,7 @@ export default function Page() { Hover me - + @@ -34,7 +34,7 @@ export default function Page() { Over me - + diff --git a/examples/svelte-ts/package.json b/examples/svelte-ts/package.json index 9dc0c8c1af..9c8874415d 100644 --- a/examples/svelte-ts/package.json +++ b/examples/svelte-ts/package.json @@ -79,7 +79,6 @@ "@zag-js/tree-view": "workspace:*", "@zag-js/types": "workspace:*", "@zag-js/utils": "workspace:*", - "@zag-js/visually-hidden": "workspace:*", "form-serialize": "0.7.2", "match-sorter": "6.3.4", "lucide-svelte": "0.372.0", diff --git a/examples/svelte-ts/src/lib/components/toast-item.svelte b/examples/svelte-ts/src/lib/components/toast-item.svelte index 4defff7ff5..a3a23cd578 100644 --- a/examples/svelte-ts/src/lib/components/toast-item.svelte +++ b/examples/svelte-ts/src/lib/components/toast-item.svelte @@ -1,6 +1,7 @@ - - - {api.title} - {api.description} - Close - + + + {api.title} + {api.description} + + + + diff --git a/examples/svelte-ts/src/routes/accordion.svelte b/examples/svelte-ts/src/routes/accordion.svelte index 1ad9cf8e5f..155564898b 100644 --- a/examples/svelte-ts/src/routes/accordion.svelte +++ b/examples/svelte-ts/src/routes/accordion.svelte @@ -9,11 +9,11 @@ const controls = useControls(accordionControls) - const [_state, send] = useMachine(accordion.machine({ id: "1" }), { + const [snapshot, send] = useMachine(accordion.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(accordion.connect(_state, send, normalizeProps)) + const api = $derived(accordion.connect(snapshot, send, normalizeProps)) @@ -38,5 +38,5 @@ - + diff --git a/examples/svelte-ts/src/routes/avatar.svelte b/examples/svelte-ts/src/routes/avatar.svelte index 85f47bb29b..7f8e9d00e0 100644 --- a/examples/svelte-ts/src/routes/avatar.svelte +++ b/examples/svelte-ts/src/routes/avatar.svelte @@ -11,8 +11,8 @@ let src = $state(images[0]) let showImage = $state(true) - const [_state, send] = useMachine(avatar.machine({ id: "1" })) - const api = $derived(avatar.connect(_state, send, normalizeProps)) + const [snapshot, send] = useMachine(avatar.machine({ id: "1" })) + const api = $derived(avatar.connect(snapshot, send, normalizeProps)) @@ -31,5 +31,5 @@ - + diff --git a/examples/svelte-ts/src/routes/carousel.svelte b/examples/svelte-ts/src/routes/carousel.svelte index 56d238d2f1..cf168d6005 100644 --- a/examples/svelte-ts/src/routes/carousel.svelte +++ b/examples/svelte-ts/src/routes/carousel.svelte @@ -8,11 +8,11 @@ const controls = useControls(carouselControls) - const [_state, send] = useMachine(carousel.machine({ id: "1", index: 0, spacing: "20px", slidesPerView: 2 }), { + const [snapshot, send] = useMachine(carousel.machine({ id: "1", index: 0, spacing: "20px", slidesPerView: 2 }), { // context: controls.context, }) - const api = $derived(carousel.connect(_state, send, normalizeProps)) + const api = $derived(carousel.connect(snapshot, send, normalizeProps)) @@ -32,5 +32,5 @@ - + diff --git a/examples/svelte-ts/src/routes/checkbox.svelte b/examples/svelte-ts/src/routes/checkbox.svelte index 8066ec2d01..b6afdd4d5b 100644 --- a/examples/svelte-ts/src/routes/checkbox.svelte +++ b/examples/svelte-ts/src/routes/checkbox.svelte @@ -9,11 +9,11 @@ const controls = useControls(checkboxControls) - const [_state, send] = useMachine(checkbox.machine({ id: "1" }), { + const [snapshot, send] = useMachine(checkbox.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(checkbox.connect(_state, send, normalizeProps)) + const api = $derived(checkbox.connect(snapshot, send, normalizeProps)) @@ -25,19 +25,19 @@ > - - Input {api.isChecked ? "Checked" : "Unchecked"} + + Input {api.checked ? "Checked" : "Unchecked"} Indicator - api.setChecked(true)}>Check - api.setChecked(false)}>Uncheck + api.setChecked(true)}>Check + api.setChecked(false)}>Uncheck Reset Form - + diff --git a/examples/svelte-ts/src/routes/clipboard.svelte b/examples/svelte-ts/src/routes/clipboard.svelte index 0e8c2ca9d5..b738a8ade6 100644 --- a/examples/svelte-ts/src/routes/clipboard.svelte +++ b/examples/svelte-ts/src/routes/clipboard.svelte @@ -9,7 +9,7 @@ const controls = useControls(clipboardControls) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( clipboard.machine({ id: "1", value: "https://github/com/chakra-ui/zag", @@ -19,7 +19,7 @@ }, ) - const api = $derived(clipboard.connect(_state, send, normalizeProps)) + const api = $derived(clipboard.connect(snapshot, send, normalizeProps)) @@ -29,7 +29,7 @@ - {#if api.isCopied} + {#if api.copied} {:else} @@ -42,5 +42,5 @@ - + diff --git a/examples/svelte-ts/src/routes/collapsible.svelte b/examples/svelte-ts/src/routes/collapsible.svelte index f3dc09de4b..38213d6bba 100644 --- a/examples/svelte-ts/src/routes/collapsible.svelte +++ b/examples/svelte-ts/src/routes/collapsible.svelte @@ -8,11 +8,11 @@ const controls = useControls(collapsibleControls) - const [_state, send] = useMachine(collapsible.machine({ id: "1" }), { + const [snapshot, send] = useMachine(collapsible.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(collapsible.connect(_state, send, normalizeProps)) + const api = $derived(collapsible.connect(snapshot, send, normalizeProps)) @@ -31,11 +31,11 @@ Toggle Controls - Open - Close + api.setOpen(true)}>Open + api.setOpen(false)}>Close - + diff --git a/examples/svelte-ts/src/routes/color-picker.svelte b/examples/svelte-ts/src/routes/color-picker.svelte index 5f67febf57..8907223454 100644 --- a/examples/svelte-ts/src/routes/color-picker.svelte +++ b/examples/svelte-ts/src/routes/color-picker.svelte @@ -11,7 +11,7 @@ const controls = useControls(colorPickerControls) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( colorPicker.machine({ id: "1", name: "color", @@ -23,7 +23,7 @@ }, ) - const api = $derived(colorPicker.connect(_state, send, normalizeProps)) + const api = $derived(colorPicker.connect(snapshot, send, normalizeProps)) @@ -128,7 +128,7 @@ - + {#snippet EyeDropIcon()} diff --git a/examples/svelte-ts/src/routes/combobox.svelte b/examples/svelte-ts/src/routes/combobox.svelte index 911bc12e9b..3fb252f673 100644 --- a/examples/svelte-ts/src/routes/combobox.svelte +++ b/examples/svelte-ts/src/routes/combobox.svelte @@ -19,7 +19,7 @@ controls.setContext("collection", collection) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( combobox.machine({ id: "1", collection, @@ -39,7 +39,7 @@ }, ) - const api = $derived(combobox.connect(_state, send, normalizeProps)) + const api = $derived(combobox.connect(snapshot, send, normalizeProps)) $inspect(api.inputValue) @@ -71,5 +71,5 @@ - + diff --git a/examples/svelte-ts/src/routes/context-menu.svelte b/examples/svelte-ts/src/routes/context-menu.svelte index 8db193d270..7733fc7946 100644 --- a/examples/svelte-ts/src/routes/context-menu.svelte +++ b/examples/svelte-ts/src/routes/context-menu.svelte @@ -4,14 +4,14 @@ import * as menu from "@zag-js/menu" import { normalizeProps, portal, useMachine } from "@zag-js/svelte" - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( menu.machine({ id: "1", onSelect: console.log, }), ) - const api = $derived(menu.connect(_state, send, normalizeProps)) + const api = $derived(menu.connect(snapshot, send, normalizeProps)) @@ -27,5 +27,5 @@ - + diff --git a/examples/svelte-ts/src/routes/file-upload.svelte b/examples/svelte-ts/src/routes/file-upload.svelte index 17e4c44ae0..4d4fa1eea8 100644 --- a/examples/svelte-ts/src/routes/file-upload.svelte +++ b/examples/svelte-ts/src/routes/file-upload.svelte @@ -8,11 +8,11 @@ const controls = useControls(fileUploadControls) - const [state, send] = useMachine(fileUpload.machine({ id: "1" }), { + const [snapshot, send] = useMachine(fileUpload.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(fileUpload.connect(state, send, normalizeProps)) + const api = $derived(fileUpload.connect(snapshot, send, normalizeProps)) @@ -40,5 +40,5 @@ - + diff --git a/examples/svelte-ts/src/routes/floating-panel.svelte b/examples/svelte-ts/src/routes/floating-panel.svelte index 332450b06b..c6b14e79fa 100644 --- a/examples/svelte-ts/src/routes/floating-panel.svelte +++ b/examples/svelte-ts/src/routes/floating-panel.svelte @@ -9,11 +9,11 @@ const controls = useControls(floatingPanelControls) - const [_state, send] = useMachine(floatingPanel.machine({ id: "1" }), { + const [snapshot, send] = useMachine(floatingPanel.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(floatingPanel.connect(_state, send, normalizeProps)) + const api = $derived(floatingPanel.connect(snapshot, send, normalizeProps)) @@ -58,5 +58,5 @@ - + diff --git a/examples/svelte-ts/src/routes/hover-card.svelte b/examples/svelte-ts/src/routes/hover-card.svelte index ee8de30b40..0da60ac927 100644 --- a/examples/svelte-ts/src/routes/hover-card.svelte +++ b/examples/svelte-ts/src/routes/hover-card.svelte @@ -8,22 +8,22 @@ const controls = useControls(hoverCardControls) - const [state, send] = useMachine(hoverCard.machine({ id: "1" }), { + const [snapshot, send] = useMachine(hoverCard.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(hoverCard.connect(state, send, normalizeProps)) + const api = $derived(hoverCard.connect(snapshot, send, normalizeProps)) Twitter - {#if api.isOpen} + {#if api.open} - + Twitter Preview Twitter @@ -36,5 +36,5 @@ - + diff --git a/examples/svelte-ts/src/routes/menu-options.svelte b/examples/svelte-ts/src/routes/menu-options.svelte index ecb154336b..cabbc699b3 100644 --- a/examples/svelte-ts/src/routes/menu-options.svelte +++ b/examples/svelte-ts/src/routes/menu-options.svelte @@ -11,11 +11,11 @@ let order = $state("") let type = $state([]) - const [_state, send] = useMachine(menu.machine({ id: "1" }), { + const [snapshot, send] = useMachine(menu.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(menu.connect(_state, send, normalizeProps)) + const api = $derived(menu.connect(snapshot, send, normalizeProps)) const radios = $derived( menuOptionData.order.map((item) => ({ @@ -71,5 +71,5 @@ - + diff --git a/examples/svelte-ts/src/routes/menu.svelte b/examples/svelte-ts/src/routes/menu.svelte index 4459ccef1b..7d277a4db5 100644 --- a/examples/svelte-ts/src/routes/menu.svelte +++ b/examples/svelte-ts/src/routes/menu.svelte @@ -8,11 +8,11 @@ const controls = useControls(menuControls) - const [state, send] = useMachine(menu.machine({ id: "1", onSelect: console.log }), { + const [snapshot, send] = useMachine(menu.machine({ id: "1", onSelect: console.log }), { context: controls.context, }) - const api = $derived(menu.connect(state, send, normalizeProps)) + const api = $derived(menu.connect(snapshot, send, normalizeProps)) @@ -32,5 +32,5 @@ - + diff --git a/examples/svelte-ts/src/routes/number-input.svelte b/examples/svelte-ts/src/routes/number-input.svelte index 433145fd4d..71d8a9a347 100644 --- a/examples/svelte-ts/src/routes/number-input.svelte +++ b/examples/svelte-ts/src/routes/number-input.svelte @@ -8,16 +8,16 @@ const controls = useControls(numberInputControls) - const [_state, send] = useMachine(numberInput.machine({ id: "1" }), { + const [snapshot, send] = useMachine(numberInput.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(numberInput.connect(_state, send, normalizeProps)) + const api = $derived(numberInput.connect(snapshot, send, normalizeProps)) - + Enter number: @@ -29,5 +29,5 @@ - + diff --git a/examples/svelte-ts/src/routes/pagination.svelte b/examples/svelte-ts/src/routes/pagination.svelte index 18f3c426d9..7a8cf7b012 100644 --- a/examples/svelte-ts/src/routes/pagination.svelte +++ b/examples/svelte-ts/src/routes/pagination.svelte @@ -9,7 +9,7 @@ const controls = useControls(paginationControls) let details = $state({}) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( pagination.machine({ id: "1", count: paginationData.length, @@ -22,7 +22,7 @@ }, ) - const api = $derived(pagination.connect(_state, send, normalizeProps)) + const api = $derived(pagination.connect(snapshot, send, normalizeProps)) const data = $derived(api.slice(paginationData)) @@ -82,5 +82,5 @@ - + diff --git a/examples/svelte-ts/src/routes/pin-input.svelte b/examples/svelte-ts/src/routes/pin-input.svelte index eee5614dd5..4e6b2f7a5e 100644 --- a/examples/svelte-ts/src/routes/pin-input.svelte +++ b/examples/svelte-ts/src/routes/pin-input.svelte @@ -9,7 +9,7 @@ const controls = useControls(pinInputControls) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( pinInput.machine({ name: "test", id: "1", @@ -19,7 +19,7 @@ }, ) - const api = $derived(pinInput.connect(_state, send, normalizeProps)) + const api = $derived(pinInput.connect(snapshot, send, normalizeProps)) @@ -46,5 +46,5 @@ - + diff --git a/examples/svelte-ts/src/routes/popover.svelte b/examples/svelte-ts/src/routes/popover.svelte index f901b26b5b..1c0f5589fb 100644 --- a/examples/svelte-ts/src/routes/popover.svelte +++ b/examples/svelte-ts/src/routes/popover.svelte @@ -8,11 +8,11 @@ const controls = useControls(popoverControls) - const [state, send] = useMachine(popover.machine({ id: "1" }), { + const [snapshot, send] = useMachine(popover.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(popover.connect(state, send, normalizeProps)) + const api = $derived(popover.connect(snapshot, send, normalizeProps)) @@ -29,7 +29,7 @@ - + Popover Title @@ -48,5 +48,5 @@ - + diff --git a/examples/svelte-ts/src/routes/progress.svelte b/examples/svelte-ts/src/routes/progress.svelte index 4a4233940e..744cc5f177 100644 --- a/examples/svelte-ts/src/routes/progress.svelte +++ b/examples/svelte-ts/src/routes/progress.svelte @@ -8,11 +8,11 @@ const controls = useControls(progressControls) - const [_state, send] = useMachine(progress.machine({ id: "1" }), { + const [snapshot, send] = useMachine(progress.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(progress.connect(_state, send, normalizeProps)) + const api = $derived(progress.connect(snapshot, send, normalizeProps)) @@ -25,7 +25,7 @@ - + {api.valueAsString} @@ -39,5 +39,5 @@ - + diff --git a/examples/svelte-ts/src/routes/radio-group.svelte b/examples/svelte-ts/src/routes/radio-group.svelte index 76070535dd..111ab8046a 100644 --- a/examples/svelte-ts/src/routes/radio-group.svelte +++ b/examples/svelte-ts/src/routes/radio-group.svelte @@ -9,11 +9,11 @@ const controls = useControls(radioControls) - const [state, send] = useMachine(radio.machine({ id: "1", name: "fruit" }), { + const [snapshot, send] = useMachine(radio.machine({ id: "1", name: "fruit" }), { context: controls.context, }) - const api = $derived(radio.connect(state, send, normalizeProps)) + const api = $derived(radio.connect(snapshot, send, normalizeProps)) @@ -26,10 +26,10 @@ Fruits - + {#each radioData as opt} - + {opt.label} @@ -47,5 +47,5 @@ - + diff --git a/examples/svelte-ts/src/routes/range-slider.svelte b/examples/svelte-ts/src/routes/range-slider.svelte index 0213cab1b7..e091e846e4 100644 --- a/examples/svelte-ts/src/routes/range-slider.svelte +++ b/examples/svelte-ts/src/routes/range-slider.svelte @@ -9,7 +9,7 @@ const controls = useControls(sliderControls) - const [state, send] = useMachine( + const [snapshot, send] = useMachine( slider.machine({ id: "1", name: "quantity", @@ -18,7 +18,7 @@ { context: controls.context }, ) - const api = $derived(slider.connect(state, send, normalizeProps)) + const api = $derived(slider.connect(snapshot, send, normalizeProps)) @@ -37,7 +37,7 @@ - + {#each api.value as _, index} @@ -57,5 +57,5 @@ - + diff --git a/examples/svelte-ts/src/routes/rating-group.svelte b/examples/svelte-ts/src/routes/rating-group.svelte index 9eb49779cb..0b0b648801 100644 --- a/examples/svelte-ts/src/routes/rating-group.svelte +++ b/examples/svelte-ts/src/routes/rating-group.svelte @@ -8,11 +8,11 @@ const controls = useControls(ratingControls) - const [state, send] = useMachine(rating.machine({ id: "1", value: 2.5 }), { + const [snapshot, send] = useMachine(rating.machine({ id: "1", value: 2.5 }), { context: controls.context, }) - const api = $derived(rating.connect(state, send, normalizeProps)) + const api = $derived(rating.connect(snapshot, send, normalizeProps)) {#snippet HalfStar()} @@ -50,7 +50,7 @@ {#each api.items as index} {@const itemState = api.getItemState({ index })} - {#if itemState.isHalf} + {#if itemState.half} {@render HalfStar()} {:else} {@render Star()} @@ -65,5 +65,5 @@ - + diff --git a/examples/svelte-ts/src/routes/segment-control.svelte b/examples/svelte-ts/src/routes/segment-control.svelte index 09760f00c9..b0c0bdea9c 100644 --- a/examples/svelte-ts/src/routes/segment-control.svelte +++ b/examples/svelte-ts/src/routes/segment-control.svelte @@ -8,16 +8,16 @@ const controls = useControls(radioControls) - const [state, send] = useMachine(radio.machine({ id: "2", name: "fruit", orientation: "horizontal" }), { + const [snapshot, send] = useMachine(radio.machine({ id: "2", name: "fruit", orientation: "horizontal" }), { context: controls.context, }) - const api = $derived(radio.connect(state, send, normalizeProps)) + const api = $derived(radio.connect(snapshot, send, normalizeProps)) - + {#each radioData as opt} @@ -31,5 +31,5 @@ - + diff --git a/examples/svelte-ts/src/routes/select.svelte b/examples/svelte-ts/src/routes/select.svelte index c9ac118008..6c920ebcdd 100644 --- a/examples/svelte-ts/src/routes/select.svelte +++ b/examples/svelte-ts/src/routes/select.svelte @@ -9,7 +9,7 @@ const controls = useControls(selectControls) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( select.machine({ id: "1", name: "select", @@ -20,7 +20,7 @@ }, ) - const api = $derived(select.connect(_state, send, normalizeProps)) + const api = $derived(select.connect(snapshot, send, normalizeProps)) @@ -71,5 +71,5 @@ - + diff --git a/examples/svelte-ts/src/routes/signature-pad.svelte b/examples/svelte-ts/src/routes/signature-pad.svelte index 12cf0d019e..4682c3dc86 100644 --- a/examples/svelte-ts/src/routes/signature-pad.svelte +++ b/examples/svelte-ts/src/routes/signature-pad.svelte @@ -12,7 +12,7 @@ let url = $state("") const setUrl = (value: string) => (url = value) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( signaturePad.machine({ id: "1", onDrawEnd(details) { @@ -29,7 +29,7 @@ }, ) - const api = $derived(signaturePad.connect(_state, send, normalizeProps)) + const api = $derived(signaturePad.connect(snapshot, send, normalizeProps)) @@ -69,5 +69,5 @@ - + diff --git a/examples/svelte-ts/src/routes/slider.svelte b/examples/svelte-ts/src/routes/slider.svelte index af2fa2c5ba..2082542b29 100644 --- a/examples/svelte-ts/src/routes/slider.svelte +++ b/examples/svelte-ts/src/routes/slider.svelte @@ -9,7 +9,7 @@ const controls = useControls(sliderControls) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( slider.machine({ id: "1", name: "quantity", @@ -20,7 +20,7 @@ }, ) - const api = $derived(slider.connect(_state, send, normalizeProps)) + const api = $derived(slider.connect(snapshot, send, normalizeProps)) @@ -60,5 +60,5 @@ - + diff --git a/examples/svelte-ts/src/routes/switch.svelte b/examples/svelte-ts/src/routes/switch.svelte index 5b643b2708..dc497cfc5f 100644 --- a/examples/svelte-ts/src/routes/switch.svelte +++ b/examples/svelte-ts/src/routes/switch.svelte @@ -8,11 +8,11 @@ const controls = useControls(switchControls) - const [state, send] = useMachine(zagSwitch.machine({ id: "1", name: "switch" }), { + const [snapshot, send] = useMachine(zagSwitch.machine({ id: "1", name: "switch" }), { context: controls.context, }) - const api = $derived(zagSwitch.connect(state, send, normalizeProps)) + const api = $derived(zagSwitch.connect(snapshot, send, normalizeProps)) @@ -20,12 +20,12 @@ - + - Feature is {api.isChecked ? "enabled" : "disabled"} + Feature is {api.checked ? "enabled" : "disabled"} - + diff --git a/examples/svelte-ts/src/routes/tabs.svelte b/examples/svelte-ts/src/routes/tabs.svelte index f3419dab4c..9591f2505d 100644 --- a/examples/svelte-ts/src/routes/tabs.svelte +++ b/examples/svelte-ts/src/routes/tabs.svelte @@ -8,7 +8,7 @@ const controls = useControls(tabsControls) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( tabs.machine({ id: "1", value: "nils", @@ -18,12 +18,12 @@ }, ) - const api = $derived(tabs.connect(_state, send, normalizeProps)) + const api = $derived(tabs.connect(snapshot, send, normalizeProps)) - + {#each tabsData as data} @@ -44,5 +44,5 @@ - + diff --git a/examples/svelte-ts/src/routes/tags-input.svelte b/examples/svelte-ts/src/routes/tags-input.svelte index 1cfe03fef5..f832d7a26f 100644 --- a/examples/svelte-ts/src/routes/tags-input.svelte +++ b/examples/svelte-ts/src/routes/tags-input.svelte @@ -12,7 +12,7 @@ const controls = useControls(tagsInputControls) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( tagsInput.machine({ id: "1", value: ["React", "Vue"], @@ -22,7 +22,7 @@ }, ) - const api = $derived(tagsInput.connect(_state, send, normalizeProps)) + const api = $derived(tagsInput.connect(snapshot, send, normalizeProps)) @@ -54,5 +54,5 @@ - + diff --git a/examples/svelte-ts/src/routes/toast.svelte b/examples/svelte-ts/src/routes/toast.svelte index 44d5a1bbe1..97f11649ff 100644 --- a/examples/svelte-ts/src/routes/toast.svelte +++ b/examples/svelte-ts/src/routes/toast.svelte @@ -9,7 +9,7 @@ const controls = useControls(toastControls) - const [state, send] = useMachine( + const [snapshot, send] = useMachine( toast.group.machine({ id: "1", placement: "bottom-end", @@ -21,7 +21,7 @@ }, ) - const api = $derived(toast.group.connect(state, send, normalizeProps)) + const api = $derived(toast.group.connect(snapshot, send, normalizeProps)) let id: string | undefined = "" @@ -73,5 +73,5 @@ - + diff --git a/examples/svelte-ts/src/routes/toggle-group.svelte b/examples/svelte-ts/src/routes/toggle-group.svelte index ad8f226d4b..0d58f6fc0f 100644 --- a/examples/svelte-ts/src/routes/toggle-group.svelte +++ b/examples/svelte-ts/src/routes/toggle-group.svelte @@ -8,11 +8,11 @@ const controls = useControls(toggleGroupControls) - const [_state, send] = useMachine(toggle.machine({ id: "1" }), { + const [snapshot, send] = useMachine(toggle.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(toggle.connect(_state, send, normalizeProps)) + const api = $derived(toggle.connect(snapshot, send, normalizeProps)) @@ -27,5 +27,5 @@ - + diff --git a/examples/svelte-ts/src/routes/tooltip.svelte b/examples/svelte-ts/src/routes/tooltip.svelte index 49771ece97..1402169fdf 100644 --- a/examples/svelte-ts/src/routes/tooltip.svelte +++ b/examples/svelte-ts/src/routes/tooltip.svelte @@ -7,23 +7,23 @@ const id = "tip-1" const id2 = "tip-2" - const [_state, send] = useMachine(tooltip.machine({ id })) - const [_state2, send2] = useMachine(tooltip.machine({ id: id2 })) + const [snapshot, send] = useMachine(tooltip.machine({ id })) + const [snapshot2, send2] = useMachine(tooltip.machine({ id: id2 })) - const api = $derived(tooltip.connect(_state, send, normalizeProps)) - const api2 = $derived(tooltip.connect(_state2, send2, normalizeProps)) + const api = $derived(tooltip.connect(snapshot, send, normalizeProps)) + const api2 = $derived(tooltip.connect(snapshot2, send2, normalizeProps)) Hover me - {#if api.isOpen} + {#if api.open} Tooltip {/if} Over me - {#if api2.isOpen} + {#if api2.open} Tooltip 2 @@ -32,6 +32,6 @@ - - + + diff --git a/examples/svelte-ts/src/routes/tour.svelte b/examples/svelte-ts/src/routes/tour.svelte index 83a7e1ac6a..560698f068 100644 --- a/examples/svelte-ts/src/routes/tour.svelte +++ b/examples/svelte-ts/src/routes/tour.svelte @@ -7,11 +7,11 @@ const controls = useControls(tourControls) - const [state, send] = useMachine(tour.machine({ id: "1", steps: tourData }), { + const [snapshot, send] = useMachine(tour.machine({ id: "1", steps: tourData }), { context: controls.context, }) - const api = $derived(tour.connect(state, send, normalizeProps)) + const api = $derived(tour.connect(snapshot, send, normalizeProps)) @@ -20,9 +20,9 @@ Step 1 - + Step 2 - + Iframe Content @@ -37,13 +37,13 @@ - - + + {#if api.currentStep} - + {api.currentStep.title} {api.currentStep.description} diff --git a/examples/svelte-ts/src/routes/tree-view.svelte b/examples/svelte-ts/src/routes/tree-view.svelte index f3026b886a..5d8c97de7e 100644 --- a/examples/svelte-ts/src/routes/tree-view.svelte +++ b/examples/svelte-ts/src/routes/tree-view.svelte @@ -8,11 +8,11 @@ const controls = useControls(treeviewControls) - const [state, send] = useMachine(tree.machine({ id: "1" }), { + const [snapshot, send] = useMachine(tree.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(tree.connect(state, send, normalizeProps)) + const api = $derived(tree.connect(snapshot, send, normalizeProps)) @@ -69,5 +69,5 @@ - + diff --git a/examples/vue-ts/package.json b/examples/vue-ts/package.json index 63811422f6..baef86a282 100644 --- a/examples/vue-ts/package.json +++ b/examples/vue-ts/package.json @@ -78,7 +78,6 @@ "@zag-js/tree-view": "workspace:*", "@zag-js/types": "workspace:*", "@zag-js/utils": "workspace:*", - "@zag-js/visually-hidden": "workspace:*", "@zag-js/vue": "workspace:*", "epic-spinners": "2.0.0", "form-serialize": "0.7.2", diff --git a/examples/vue-ts/src/pages/checkbox.tsx b/examples/vue-ts/src/pages/checkbox.tsx index f5b1af4eb6..f494d7d5f5 100644 --- a/examples/vue-ts/src/pages/checkbox.tsx +++ b/examples/vue-ts/src/pages/checkbox.tsx @@ -39,15 +39,15 @@ export default defineComponent({ - Input {api.isChecked ? "Checked" : "Unchecked"} + Input {api.checked ? "Checked" : "Unchecked"} Indicator - api.setChecked(true)}> + api.setChecked(true)}> Check - api.setChecked(false)}> + api.setChecked(false)}> Uncheck Reset Form diff --git a/examples/vue-ts/src/pages/clipboard.tsx b/examples/vue-ts/src/pages/clipboard.tsx index bd69e93881..452ec460fb 100644 --- a/examples/vue-ts/src/pages/clipboard.tsx +++ b/examples/vue-ts/src/pages/clipboard.tsx @@ -34,7 +34,7 @@ export default defineComponent({ Copy this link - {api.isCopied ? : } + {api.copied ? : } Copied! Copy diff --git a/examples/vue-ts/src/pages/collapsible.tsx b/examples/vue-ts/src/pages/collapsible.tsx index 8c4b204e92..5eda24b437 100644 --- a/examples/vue-ts/src/pages/collapsible.tsx +++ b/examples/vue-ts/src/pages/collapsible.tsx @@ -38,8 +38,8 @@ export default defineComponent({ Toggle Controls - Open - Close + api.setOpen(true)}>Open + api.setOpen(false)}>Close diff --git a/examples/vue-ts/src/pages/date-picker.tsx b/examples/vue-ts/src/pages/date-picker.tsx index 0c8ea2cd36..91c056739c 100644 --- a/examples/vue-ts/src/pages/date-picker.tsx +++ b/examples/vue-ts/src/pages/date-picker.tsx @@ -45,7 +45,7 @@ export default defineComponent({ - + ❌ 🗓 diff --git a/examples/vue-ts/src/pages/dialog.tsx b/examples/vue-ts/src/pages/dialog.tsx index d6310f7fd4..ea6e184f1d 100644 --- a/examples/vue-ts/src/pages/dialog.tsx +++ b/examples/vue-ts/src/pages/dialog.tsx @@ -30,7 +30,7 @@ export default defineComponent({ Open Dialog - {parentDialog.isOpen && ( + {parentDialog.open && ( @@ -47,7 +47,7 @@ export default defineComponent({ Open Nested - {childDialog.isOpen && ( + {childDialog.open && ( @@ -55,7 +55,7 @@ export default defineComponent({ X - parentDialog.close()} data-testid="special-close"> + parentDialog.setOpen(false)} data-testid="special-close"> Close Dialog 1 diff --git a/examples/vue-ts/src/pages/editable.tsx b/examples/vue-ts/src/pages/editable.tsx index 18c1fae366..37238315e2 100644 --- a/examples/vue-ts/src/pages/editable.tsx +++ b/examples/vue-ts/src/pages/editable.tsx @@ -29,12 +29,12 @@ export default defineComponent({ - {!api.isEditing && ( + {!api.editing && ( Edit )} - {api.isEditing && ( + {api.editing && ( <> Save diff --git a/examples/vue-ts/src/pages/hover-card.tsx b/examples/vue-ts/src/pages/hover-card.tsx index e7539bef97..9b6f4463e7 100644 --- a/examples/vue-ts/src/pages/hover-card.tsx +++ b/examples/vue-ts/src/pages/hover-card.tsx @@ -28,7 +28,7 @@ export default defineComponent({ Twitter - {api.isOpen && ( + {api.open && ( diff --git a/examples/vue-ts/src/pages/pagination.tsx b/examples/vue-ts/src/pages/pagination.tsx index 7540cc9caf..6c2f2a9bf9 100644 --- a/examples/vue-ts/src/pages/pagination.tsx +++ b/examples/vue-ts/src/pages/pagination.tsx @@ -1,6 +1,5 @@ import * as pagination from "@zag-js/pagination" import { normalizeProps, useMachine } from "@zag-js/vue" -import { visuallyHiddenStyle } from "@zag-js/visually-hidden" import { computed, defineComponent, h, Fragment } from "vue" import { paginationControls, paginationData } from "@zag-js/shared" import { StateVisualizer } from "../components/state-visualizer" @@ -60,9 +59,7 @@ export default defineComponent({ - - Previous Page - + Previous {api.pages.map((page, i) => { if (page.type === "page") @@ -81,9 +78,7 @@ export default defineComponent({ ) })} - - Next Page - + Next diff --git a/examples/vue-ts/src/pages/presence.tsx b/examples/vue-ts/src/pages/presence.tsx index 9d9ebab424..0c889bf9bb 100644 --- a/examples/vue-ts/src/pages/presence.tsx +++ b/examples/vue-ts/src/pages/presence.tsx @@ -26,7 +26,7 @@ export default defineComponent({ return ( (present.value = !present.value)}>Toggle - {api.isPresent && ( + {api.present && ( Content diff --git a/examples/vue-ts/src/pages/rating-group.tsx b/examples/vue-ts/src/pages/rating-group.tsx index b65dfecca6..5c4fbaff77 100644 --- a/examples/vue-ts/src/pages/rating-group.tsx +++ b/examples/vue-ts/src/pages/rating-group.tsx @@ -71,7 +71,7 @@ export default defineComponent({ const state = api.getItemState({ index }) return ( - {state.isHalf ? : } + {state.half ? : } ) })} diff --git a/examples/vue-ts/src/pages/switch.tsx b/examples/vue-ts/src/pages/switch.tsx index d9f7265bfb..2904483c8b 100644 --- a/examples/vue-ts/src/pages/switch.tsx +++ b/examples/vue-ts/src/pages/switch.tsx @@ -34,7 +34,7 @@ export default defineComponent({ - Feature is {api.isChecked ? "enabled" : "disabled"} + Feature is {api.checked ? "enabled" : "disabled"} diff --git a/examples/vue-ts/src/pages/toast.tsx b/examples/vue-ts/src/pages/toast.tsx index ccb081aeab..0460bcc005 100644 --- a/examples/vue-ts/src/pages/toast.tsx +++ b/examples/vue-ts/src/pages/toast.tsx @@ -19,26 +19,13 @@ const ToastItem = defineComponent({ setup(props) { const [state, send] = useActor(props.actor) const apiRef = computed(() => toast.connect(state.value, send, normalizeProps)) - const progressbarProps = computed(() => ({ - "data-scope": "toast", - "data-part": "progressbar", - "data-type": state.value.context.type, - style: { - opacity: apiRef.value.isVisible ? 1 : 0, - transformOrigin: apiRef.value.isRtl ? "right" : "left", - animationName: apiRef.value.type === "loading" ? "none" : undefined, - animationPlayState: apiRef.value.isPaused ? "paused" : "running", - animationDuration: "var(--duration)", - }, - })) - return () => { const api = apiRef.value return ( - + - + {api.type === "loading" && } {api.title} @@ -47,7 +34,7 @@ const ToastItem = defineComponent({ - + ) } }, diff --git a/examples/vue-ts/src/pages/tooltip.tsx b/examples/vue-ts/src/pages/tooltip.tsx index 824574adf3..a063f1ccc8 100644 --- a/examples/vue-ts/src/pages/tooltip.tsx +++ b/examples/vue-ts/src/pages/tooltip.tsx @@ -21,7 +21,7 @@ export default defineComponent({ Hover me - {api.isOpen && ( + {api.open && ( @@ -32,7 +32,7 @@ export default defineComponent({ )} Over me - {api2.isOpen && ( + {api2.open && ( diff --git a/packages/docs/data/api.json b/packages/docs/data/api.json index 2f23dd59b0..2365af393a 100644 --- a/packages/docs/data/api.json +++ b/packages/docs/data/api.json @@ -70,14 +70,10 @@ }, "avatar": { "api": { - "isLoaded": { + "loaded": { "type": "boolean", "description": "Whether the image is loaded." }, - "showFallback": { - "type": "boolean", - "description": "Whether the fallback is shown." - }, "setSrc": { "type": "(src: string) => void", "description": "Function to set new src." @@ -121,9 +117,9 @@ "type": "number", "description": "The current scroll progress of the carousel" }, - "isAutoplay": { + "autoPlaying": { "type": "boolean", - "description": "Whether the carousel is currently auto-playing" + "description": "Whether the carousel is auto playing" }, "canScrollNext": { "type": "boolean", @@ -209,19 +205,19 @@ }, "checkbox": { "api": { - "isChecked": { + "checked": { "type": "boolean", "description": "Whether the checkbox is checked" }, - "isDisabled": { + "disabled": { "type": "boolean", "description": "Whether the checkbox is disabled" }, - "isIndeterminate": { + "indeterminate": { "type": "boolean", "description": "Whether the checkbox is indeterminate" }, - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the checkbox is focused" }, @@ -245,27 +241,31 @@ }, "disabled": { "type": "boolean", - "description": "If `true`, the checkbox will be disabled" + "description": "Whether the checkbox is disabled" }, "invalid": { "type": "boolean", - "description": "If `true`, the checkbox is marked as invalid." + "description": "Whether the checkbox is invalid" }, "required": { "type": "boolean", - "description": "If `true`, the checkbox input is marked as required," + "description": "Whether the checkbox is required" }, "checked": { "type": "CheckedState", - "description": "If `true`, the checkbox will be checked." + "description": "The checked state of the checkbox" + }, + "readOnly": { + "type": "boolean", + "description": "Whether the checkbox is read-only" }, "onCheckedChange": { "type": "(details: CheckedChangeDetails) => void", - "description": "The callback invoked when the checked state of the `Checkbox` changes." + "description": "The callback invoked when the checked state changes." }, "name": { "type": "string", - "description": "The name of the input field in a checkbox. Useful for form submission." + "description": "The name of the input field in a checkbox.\nUseful for form submission." }, "form": { "type": "string", @@ -293,7 +293,7 @@ }, "clipboard": { "api": { - "isCopied": { + "copied": { "type": "boolean", "description": "Whether the value has been copied to the clipboard" }, @@ -339,25 +339,21 @@ }, "collapsible": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the collapsible is open." }, - "isVisible": { + "visible": { "type": "boolean", "description": "Whether the collapsible is visible (open or closing)" }, - "isDisabled": { + "disabled": { "type": "boolean", "description": "Whether the collapsible is disabled" }, - "open": { - "type": "() => void", - "description": "Function to open the collapsible." - }, - "close": { - "type": "() => void", - "description": "Function to close the collapsible." + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the collapsible." } }, "context": { @@ -402,11 +398,11 @@ }, "color-picker": { "api": { - "isDragging": { + "dragging": { "type": "boolean", "description": "Whether the color picker is being dragged" }, - "isOpen": { + "open": { "type": "boolean", "description": "Whether the color picker is open" }, @@ -446,13 +442,9 @@ "type": "(value: number) => void", "description": "Function to set the color alpha" }, - "open": { - "type": "() => void", - "description": "Function to open the color picker" - }, - "close": { - "type": "() => void", - "description": "Function to close the color picker" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the color picker" } }, "context": { @@ -544,15 +536,15 @@ }, "combobox": { "api": { - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the combobox is focused" }, - "isOpen": { + "open": { "type": "boolean", "description": "Whether the combobox is open" }, - "isInputValueEmpty": { + "inputEmpty": { "type": "boolean", "description": "Whether the combobox input value is empty" }, @@ -612,13 +604,9 @@ "type": "(props: ItemProps) => ItemState", "description": "Returns the state of a combobox item" }, - "open": { - "type": "() => void", - "description": "Function to open the combobox" - }, - "close": { - "type": "() => void", - "description": "Function to close the combobox" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the combobox" }, "collection": { "type": "Collection", @@ -795,11 +783,11 @@ }, "date-picker": { "api": { - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the input is focused" }, - "isOpen": { + "open": { "type": "boolean", "description": "Whether the date picker is open" }, @@ -883,13 +871,9 @@ "type": "() => void", "description": "Clears the selected date(s)." }, - "open": { - "type": "() => void", - "description": "Function to open the calendar." - }, - "close": { - "type": "() => void", - "description": "Function to close the calendar." + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the calendar." }, "focusMonth": { "type": "(month: number) => void", @@ -1076,17 +1060,13 @@ }, "dialog": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the dialog is open" }, - "open": { - "type": "() => void", - "description": "Function to open the dialog" - }, - "close": { - "type": "() => void", - "description": "Function to close the dialog" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the dialog" } }, "context": { @@ -1180,11 +1160,11 @@ }, "editable": { "api": { - "isEditing": { + "editing": { "type": "boolean", "description": "Whether the editable is in edit mode" }, - "isValueEmpty": { + "empty": { "type": "boolean", "description": "Whether the editable value is empty" }, @@ -1325,15 +1305,15 @@ }, "file-upload": { "api": { - "isDragging": { + "dragging": { "type": "boolean", "description": "Whether the user is dragging something over the root element" }, - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the user is focused on the dropzone element" }, - "open": { + "openFilePicker": { "type": "() => void", "description": "Function to open the file dialog" }, @@ -1449,15 +1429,19 @@ }, "floating-panel": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the panel is open" }, - "isDragging": { + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the panel" + }, + "dragging": { "type": "boolean", "description": "Whether the panel is being dragged" }, - "isResizing": { + "resizing": { "type": "boolean", "description": "Whether the panel is being resized" } @@ -1556,18 +1540,14 @@ }, "hover-card": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the hover card is open" }, - "open": { - "type": "() => void", + "setOpen": { + "type": "(open: boolean) => void", "description": "Function to open the hover card" }, - "close": { - "type": "() => void", - "description": "Function to close the hover card" - }, "reposition": { "type": "(options?: Partial) => void", "description": "Function to reposition the popover" @@ -1619,17 +1599,13 @@ }, "menu": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the menu is open" }, - "open": { - "type": "() => void", - "description": "Function to open the menu" - }, - "close": { - "type": "() => void", - "description": "Function to close the menu" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the menu" }, "highlightedValue": { "type": "string", @@ -1746,15 +1722,15 @@ }, "number-input": { "api": { - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the input is focused." }, - "isInvalid": { + "invalid": { "type": "boolean", "description": "Whether the input is invalid." }, - "isValueEmpty": { + "empty": { "type": "boolean", "description": "Whether the input value is empty." }, @@ -1939,14 +1915,6 @@ "type": "(data: V[]) => V[]", "description": "Function to slice an array of data based on the current page." }, - "isFirstPage": { - "type": "boolean", - "description": "Whether the current page is the first page." - }, - "isLastPage": { - "type": "boolean", - "description": "Whether the current page is the last page." - }, "setCount": { "type": "(count: number) => void", "description": "Function to set the total number of pages." @@ -2019,7 +1987,7 @@ "type": "string", "description": "The value of the input as a string." }, - "isValueComplete": { + "complete": { "type": "boolean", "description": "Whether all inputs are filled." }, @@ -2134,17 +2102,13 @@ "type": "boolean", "description": "Whether the popover is portalled" }, - "isOpen": { + "open": { "type": "boolean", "description": "Whether the popover is open" }, - "open": { - "type": "() => void", - "description": "Function to open the popover" - }, - "close": { - "type": "() => void", - "description": "Function to close the popover" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the popover" }, "reposition": { "type": "(options?: Partial) => void", @@ -2231,7 +2195,7 @@ }, "presence": { "api": { - "isPresent": { + "present": { "type": "boolean", "description": "Whether the node is present in the DOM." }, @@ -2351,6 +2315,10 @@ "type": "boolean", "description": "If `true`, the radio group will be disabled" }, + "readOnly": { + "type": "boolean", + "description": "Whether the checkbox is read-only" + }, "onValueChange": { "type": "(details: ValueChangeDetails) => void", "description": "Function called once a radio is checked" @@ -2384,7 +2352,7 @@ "type": "() => void", "description": "Clears the value of the rating group" }, - "isHovering": { + "hovering": { "type": "boolean", "description": "Whether the rating group is being hovered" }, @@ -2475,15 +2443,15 @@ }, "select": { "api": { - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the select is focused" }, - "isOpen": { + "open": { "type": "boolean", "description": "Whether the select is open" }, - "isValueEmpty": { + "empty": { "type": "boolean", "description": "Whether the select value is empty" }, @@ -2535,13 +2503,9 @@ "type": "(props: ItemProps) => ItemState", "description": "Returns the state of a select item" }, - "open": { - "type": "() => void", - "description": "Function to open the select" - }, - "close": { - "type": "() => void", - "description": "Function to close the select" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the select" }, "collection": { "type": "Collection", @@ -2662,11 +2626,11 @@ }, "signature-pad": { "api": { - "isEmpty": { + "empty": { "type": "boolean", "description": "Whether the signature pad is empty." }, - "isDrawing": { + "drawing": { "type": "boolean", "description": "Whether the user is currently drawing." }, @@ -2733,11 +2697,11 @@ "type": "number[]", "description": "The value of the slider." }, - "isDragging": { + "dragging": { "type": "boolean", "description": "Whether the slider is being dragged." }, - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the slider is focused." }, @@ -2840,7 +2804,7 @@ "description": "Function invoked when the slider's focused index changes" }, "getAriaValueText": { - "type": "(value: number, index: number) => string", + "type": "(details: ValueTextDetails) => string", "description": "Function that returns a human readable value for the slider thumb" }, "min": { @@ -2892,11 +2856,11 @@ }, "splitter": { "api": { - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the splitter is focused." }, - "isDragging": { + "dragging": { "type": "boolean", "description": "Whether the splitter is being dragged." }, @@ -2959,15 +2923,15 @@ }, "switch": { "api": { - "isChecked": { + "checked": { "type": "boolean", "description": "Whether the checkbox is checked" }, - "isDisabled": { + "disabled": { "type": "boolean", "description": "Whether the checkbox is disabled" }, - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the checkbox is focused" }, @@ -3001,6 +2965,10 @@ "type": "boolean", "description": "If `true`, the switch input is marked as required," }, + "readOnly": { + "type": "boolean", + "description": "Whether the switch is read-only" + }, "onCheckedChange": { "type": "(details: CheckedChangeDetails) => void", "description": "Function to call when the switch is clicked." @@ -3117,7 +3085,7 @@ }, "tags-input": { "api": { - "isEmpty": { + "empty": { "type": "boolean", "description": "Whether the tags are empty" }, @@ -3137,7 +3105,7 @@ "type": "number", "description": "The number of the tags." }, - "isAtMax": { + "atMax": { "type": "boolean", "description": "Whether the tags have reached the max limit." }, @@ -3357,18 +3325,14 @@ }, "tooltip": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the tooltip is open." }, - "open": { - "type": "() => void", + "setOpen": { + "type": "(open: boolean) => void", "description": "Function to open the tooltip." }, - "close": { - "type": "() => void", - "description": "Function to close the tooltip." - }, "reposition": { "type": "(options?: Partial) => void", "description": "Function to reposition the popover" diff --git a/packages/machines/accordion/src/accordion.connect.ts b/packages/machines/accordion/src/accordion.connect.ts index 0314780020..5e9b6219a3 100644 --- a/packages/machines/accordion/src/accordion.connect.ts +++ b/packages/machines/accordion/src/accordion.connect.ts @@ -20,9 +20,9 @@ export function connect(state: State, send: Send, normalize function getItemState(props: ItemProps): ItemState { return { - isOpen: value.includes(props.value), - isFocused: focusedValue === props.value, - isDisabled: Boolean(props.disabled ?? state.context.disabled), + expanded: value.includes(props.value), + focused: focusedValue === props.value, + disabled: Boolean(props.disabled ?? state.context.disabled), } } @@ -45,9 +45,9 @@ export function connect(state: State, send: Send, normalize ...parts.item.attrs, dir: state.context.dir, id: dom.getItemId(state.context, props.value), - "data-state": itemState.isOpen ? "open" : "closed", - "data-focus": dataAttr(itemState.isFocused), - "data-disabled": dataAttr(itemState.isDisabled), + "data-state": itemState.expanded ? "open" : "closed", + "data-focus": dataAttr(itemState.focused), + "data-disabled": dataAttr(itemState.disabled), "data-orientation": state.context.orientation, }) }, @@ -60,10 +60,10 @@ export function connect(state: State, send: Send, normalize role: "region", id: dom.getItemContentId(state.context, props.value), "aria-labelledby": dom.getItemTriggerId(state.context, props.value), - hidden: !itemState.isOpen, - "data-state": itemState.isOpen ? "open" : "closed", - "data-disabled": dataAttr(itemState.isDisabled), - "data-focus": dataAttr(itemState.isFocused), + hidden: !itemState.expanded, + "data-state": itemState.expanded ? "open" : "closed", + "data-disabled": dataAttr(itemState.disabled), + "data-focus": dataAttr(itemState.focused), "data-orientation": state.context.orientation, }) }, @@ -74,9 +74,9 @@ export function connect(state: State, send: Send, normalize ...parts.itemIndicator.attrs, dir: state.context.dir, "aria-hidden": true, - "data-state": itemState.isOpen ? "open" : "closed", - "data-disabled": dataAttr(itemState.isDisabled), - "data-focus": dataAttr(itemState.isFocused), + "data-state": itemState.expanded ? "open" : "closed", + "data-disabled": dataAttr(itemState.disabled), + "data-focus": dataAttr(itemState.focused), "data-orientation": state.context.orientation, }) }, @@ -91,22 +91,22 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, id: dom.getItemTriggerId(state.context, value), "aria-controls": dom.getItemContentId(state.context, value), - "aria-expanded": itemState.isOpen, - disabled: itemState.isDisabled, + "aria-expanded": itemState.expanded, + disabled: itemState.disabled, "data-orientation": state.context.orientation, - "aria-disabled": itemState.isDisabled, - "data-state": itemState.isOpen ? "open" : "closed", + "aria-disabled": itemState.disabled, + "data-state": itemState.expanded ? "open" : "closed", "data-ownedby": dom.getRootId(state.context), onFocus() { - if (itemState.isDisabled) return + if (itemState.disabled) return send({ type: "TRIGGER.FOCUS", value }) }, onBlur() { - if (itemState.isDisabled) return + if (itemState.disabled) return send("TRIGGER.BLUR") }, onClick(event) { - if (itemState.isDisabled) return + if (itemState.disabled) return if (isSafari()) { event.currentTarget.focus() } @@ -114,7 +114,7 @@ export function connect(state: State, send: Send, normalize }, onKeyDown(event) { if (event.defaultPrevented) return - if (itemState.isDisabled) return + if (itemState.disabled) return const keyMap: EventKeyMap = { ArrowDown() { diff --git a/packages/machines/accordion/src/accordion.types.ts b/packages/machines/accordion/src/accordion.types.ts index 93276bd2d1..7f98b6cfe5 100644 --- a/packages/machines/accordion/src/accordion.types.ts +++ b/packages/machines/accordion/src/accordion.types.ts @@ -50,11 +50,11 @@ interface PublicContext extends DirectionProperty, CommonProperties { /** * The callback fired when the state of opened/closed accordion items changes. */ - onValueChange?: (details: ValueChangeDetails) => void + onValueChange?(details: ValueChangeDetails): void /** * The callback fired when the focused accordion item changes. */ - onFocusChange?: (details: FocusChangeDetails) => void + onFocusChange?(details: FocusChangeDetails): void /** * The orientation of the accordion items. */ @@ -94,14 +94,29 @@ export type Send = S.Send * -----------------------------------------------------------------------------*/ export interface ItemProps { + /** + * The value of the accordion item. + */ value: string + /** + * Whether the accordion item is disabled. + */ disabled?: boolean } export interface ItemState { - isOpen: boolean - isFocused: boolean - isDisabled: boolean + /** + * Whether the accordion item is expanded. + */ + expanded: boolean + /** + * Whether the accordion item is focused. + */ + focused: boolean + /** + * Whether the accordion item is disabled. + */ + disabled: boolean } export interface MachineApi { @@ -120,7 +135,8 @@ export interface MachineApi { /** * Gets the state of an accordion item. */ - getItemState: (props: ItemProps) => ItemState + getItemState(props: ItemProps): ItemState + rootProps: T["element"] getItemProps(props: ItemProps): T["element"] getItemContentProps(props: ItemProps): T["element"] diff --git a/packages/machines/avatar/src/avatar.connect.ts b/packages/machines/avatar/src/avatar.connect.ts index 2b146a8686..9d8ec7535a 100644 --- a/packages/machines/avatar/src/avatar.connect.ts +++ b/packages/machines/avatar/src/avatar.connect.ts @@ -4,12 +4,9 @@ import { dom } from "./avatar.dom" import type { MachineApi, Send, State } from "./avatar.types" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { - const isLoaded = state.matches("loaded") - const showFallback = !isLoaded - + const loaded = state.matches("loaded") return { - isLoaded, - showFallback, + loaded, setSrc(src) { send({ type: "SRC.SET", src }) }, @@ -28,10 +25,10 @@ export function connect(state: State, send: Send, normalize imageProps: normalize.img({ ...parts.image.attrs, - hidden: !isLoaded, + hidden: !loaded, dir: state.context.dir, id: dom.getImageId(state.context), - "data-state": isLoaded ? "visible" : "hidden", + "data-state": loaded ? "visible" : "hidden", onLoad() { send({ type: "IMG.LOADED", src: "element" }) }, @@ -44,8 +41,8 @@ export function connect(state: State, send: Send, normalize ...parts.fallback.attrs, dir: state.context.dir, id: dom.getFallbackId(state.context), - hidden: isLoaded, - "data-state": isLoaded ? "hidden" : "visible", + hidden: loaded, + "data-state": loaded ? "hidden" : "visible", }), } } diff --git a/packages/machines/avatar/src/avatar.types.ts b/packages/machines/avatar/src/avatar.types.ts index 28ff0eef10..6421d361e1 100644 --- a/packages/machines/avatar/src/avatar.types.ts +++ b/packages/machines/avatar/src/avatar.types.ts @@ -5,8 +5,10 @@ import type { CommonProperties, DirectionProperty, PropTypes, RequiredBy } from * Callback details * -----------------------------------------------------------------------------*/ +export type LoadStatus = "error" | "loaded" + export interface StatusChangeDetails { - status: "loaded" | "error" + status: LoadStatus } /* ----------------------------------------------------------------------------- @@ -44,11 +46,7 @@ export interface MachineApi { /** * Whether the image is loaded. */ - isLoaded: boolean - /** - * Whether the fallback is shown. - */ - showFallback: boolean + loaded: boolean /** * Function to set new src. */ diff --git a/packages/machines/avatar/src/index.ts b/packages/machines/avatar/src/index.ts index 53c0204402..4ecd5fdbc8 100644 --- a/packages/machines/avatar/src/index.ts +++ b/packages/machines/avatar/src/index.ts @@ -2,4 +2,4 @@ export { anatomy } from "./avatar.anatomy" export { connect } from "./avatar.connect" export { machine } from "./avatar.machine" export * from "./avatar.props" -export type { MachineApi as Api, UserDefinedContext as Context, StatusChangeDetails } from "./avatar.types" +export type { MachineApi as Api, UserDefinedContext as Context, StatusChangeDetails, LoadStatus } from "./avatar.types" diff --git a/packages/machines/carousel/src/carousel.connect.ts b/packages/machines/carousel/src/carousel.connect.ts index b199e93c06..810902145b 100644 --- a/packages/machines/carousel/src/carousel.connect.ts +++ b/packages/machines/carousel/src/carousel.connect.ts @@ -2,14 +2,14 @@ import { dataAttr, isDom } from "@zag-js/dom-query" import type { NormalizeProps, PropTypes } from "@zag-js/types" import { parts } from "./carousel.anatomy" import { dom } from "./carousel.dom" -import type { MachineApi, Send, IndicatorProps, ItemProps, State, ItemState } from "./carousel.types" +import type { IndicatorProps, ItemProps, ItemState, MachineApi, Send, State } from "./carousel.types" import { getSlidesInView } from "./utils/get-slide-in-view" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { const canScrollNext = state.context.canScrollNext const canScrollPrev = state.context.canScrollPrev - const isHorizontal = state.context.isHorizontal - const isAutoplay = state.matches("autoplay") + const horizontal = state.context.isHorizontal + const autoPlaying = state.matches("autoplay") const activeSnap = state.context.scrollSnaps[state.context.index] const slidesInView = isDom() ? getSlidesInView(state.context)(activeSnap) : [] @@ -18,38 +18,32 @@ export function connect(state: State, send: Send, normalize const { index } = props return { valueText: `Slide ${index + 1}`, - isCurrent: index === state.context.index, - isNext: index === state.context.index + 1, - isPrevious: index === state.context.index - 1, - isInView: slidesInView.includes(index), + current: index === state.context.index, + next: index === state.context.index + 1, + previous: index === state.context.index - 1, + inView: slidesInView.includes(index), } } return { index: state.context.index, scrollProgress: state.context.scrollProgress, - isAutoplay, + autoPlaying, canScrollNext, canScrollPrev, - scrollTo(index, jump) { send({ type: "GOTO", index, jump }) }, - scrollToNext() { send("NEXT") }, - scrollToPrevious() { send("PREV") }, - getItemState: getItemState, - play() { send("PLAY") }, - pause() { send("PAUSE") }, @@ -82,8 +76,8 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, style: { display: "flex", - flexDirection: isHorizontal ? "row" : "column", - [isHorizontal ? "height" : "width"]: "auto", + flexDirection: horizontal ? "row" : "column", + [horizontal ? "height" : "width"]: "auto", gap: "var(--slide-spacing)", transform: state.context.translateValue, transitionProperty: "transform", @@ -101,8 +95,8 @@ export function connect(state: State, send: Send, normalize ...parts.item.attrs, id: dom.getItemId(state.context, index), dir: state.context.dir, - "data-current": dataAttr(sliderState.isCurrent), - "data-inview": dataAttr(sliderState.isInView), + "data-current": dataAttr(sliderState.current), + "data-inview": dataAttr(sliderState.inView), role: "group", "aria-roledescription": "slide", "data-orientation": state.context.orientation, @@ -110,7 +104,7 @@ export function connect(state: State, send: Send, normalize style: { position: "relative", flex: "0 0 var(--slide-size)", - [isHorizontal ? "minWidth" : "minHeight"]: "0px", + [horizontal ? "minWidth" : "minHeight"]: "0px", }, }) }, diff --git a/packages/machines/carousel/src/carousel.types.ts b/packages/machines/carousel/src/carousel.types.ts index b383c1bf8e..b92e9df1bd 100644 --- a/packages/machines/carousel/src/carousel.types.ts +++ b/packages/machines/carousel/src/carousel.types.ts @@ -98,15 +98,33 @@ export type Send = S.Send * -----------------------------------------------------------------------------*/ export interface ItemProps { + /** + * The index of the item. + */ index: number } export interface ItemState { + /** + * The text value of the item. Used for accessibility. + */ valueText: string - isCurrent: boolean - isNext: boolean - isPrevious: boolean - isInView: boolean + /** + * Whether the item is the current item in the carousel + */ + current: boolean + /** + * Whether the item is the next item in the carousel + */ + next: boolean + /** + * Whether the item is the previous item in the carousel + */ + previous: boolean + /** + * Whether the item is in view + */ + inView: boolean } export interface IndicatorProps { @@ -124,9 +142,9 @@ export interface MachineApi { */ scrollProgress: number /** - * Whether the carousel is currently auto-playing + * Whether the carousel is auto playing */ - isAutoplay: boolean + autoPlaying: boolean /** * Whether the carousel is can scroll to the next slide */ diff --git a/packages/machines/checkbox/package.json b/packages/machines/checkbox/package.json index e1a9a13721..e7f490b20e 100644 --- a/packages/machines/checkbox/package.json +++ b/packages/machines/checkbox/package.json @@ -41,7 +41,6 @@ "@zag-js/types": "workspace:*", "@zag-js/dom-query": "workspace:*", "@zag-js/dom-event": "workspace:*", - "@zag-js/visually-hidden": "workspace:*", "@zag-js/form-utils": "workspace:*", "@zag-js/utils": "workspace:*" }, diff --git a/packages/machines/checkbox/src/checkbox.connect.ts b/packages/machines/checkbox/src/checkbox.connect.ts index 307448656d..ff16d983b3 100644 --- a/packages/machines/checkbox/src/checkbox.connect.ts +++ b/packages/machines/checkbox/src/checkbox.connect.ts @@ -1,38 +1,39 @@ -import { dataAttr } from "@zag-js/dom-query" +import { dataAttr, visuallyHiddenStyle } from "@zag-js/dom-query" import type { NormalizeProps, PropTypes } from "@zag-js/types" -import { visuallyHiddenStyle } from "@zag-js/visually-hidden" import { parts } from "./checkbox.anatomy" import { dom } from "./checkbox.dom" -import type { CheckedState, MachineApi, Send, State } from "./checkbox.types" +import type { MachineApi, Send, State } from "./checkbox.types" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { - const isDisabled = state.context.isDisabled - const isFocused = !isDisabled && state.context.focused - const isChecked = state.context.isChecked - const isIndeterminate = state.context.isIndeterminate + const disabled = state.context.isDisabled + const focused = !disabled && state.context.focused + const checked = state.context.isChecked + const indeterminate = state.context.isIndeterminate + const readOnly = state.context.readOnly const dataAttrs = { "data-active": dataAttr(state.context.active), - "data-focus": dataAttr(isFocused), + "data-focus": dataAttr(focused), + "data-readonly": dataAttr(readOnly), "data-hover": dataAttr(state.context.hovered), - "data-disabled": dataAttr(isDisabled), - "data-state": isIndeterminate ? "indeterminate" : state.context.checked ? "checked" : "unchecked", + "data-disabled": dataAttr(disabled), + "data-state": indeterminate ? "indeterminate" : state.context.checked ? "checked" : "unchecked", "data-invalid": dataAttr(state.context.invalid), } return { - isChecked, - isDisabled, - isIndeterminate, - isFocused, + checked, + disabled, + indeterminate, + focused, checkedState: state.context.checked, - setChecked(checked: CheckedState) { + setChecked(checked) { send({ type: "CHECKED.SET", checked, isTrusted: false }) }, toggleChecked() { - send({ type: "CHECKED.TOGGLE", checked: isChecked, isTrusted: false }) + send({ type: "CHECKED.TOGGLE", checked: checked, isTrusted: false }) }, rootProps: normalize.label({ @@ -42,11 +43,11 @@ export function connect(state: State, send: Send, normalize id: dom.getRootId(state.context), htmlFor: dom.getHiddenInputId(state.context), onPointerMove() { - if (isDisabled) return + if (disabled) return send({ type: "CONTEXT.SET", context: { hovered: true } }) }, onPointerLeave() { - if (isDisabled) return + if (disabled) return send({ type: "CONTEXT.SET", context: { hovered: false } }) }, onClick(event) { @@ -75,16 +76,16 @@ export function connect(state: State, send: Send, normalize ...parts.indicator.attrs, ...dataAttrs, dir: state.context.dir, - hidden: !isIndeterminate && !state.context.checked, + hidden: !indeterminate && !state.context.checked, }), hiddenInputProps: normalize.input({ id: dom.getHiddenInputId(state.context), type: "checkbox", required: state.context.required, - defaultChecked: isChecked, - disabled: isDisabled, - "data-disabled": dataAttr(isDisabled), + defaultChecked: checked, + disabled: disabled, + "data-disabled": dataAttr(disabled), "aria-labelledby": dom.getLabelId(state.context), "aria-invalid": state.context.invalid, name: state.context.name, @@ -92,6 +93,11 @@ export function connect(state: State, send: Send, normalize value: state.context.value, style: visuallyHiddenStyle, onChange(event) { + if (readOnly) { + event.preventDefault() + return + } + const checked = event.currentTarget.checked send({ type: "CHECKED.SET", checked, isTrusted: true }) }, diff --git a/packages/machines/checkbox/src/checkbox.props.ts b/packages/machines/checkbox/src/checkbox.props.ts index f0072b357b..46e1903a4f 100644 --- a/packages/machines/checkbox/src/checkbox.props.ts +++ b/packages/machines/checkbox/src/checkbox.props.ts @@ -13,6 +13,7 @@ export const props = createProps()([ "invalid", "name", "onCheckedChange", + "readOnly", "required", "value", ]) diff --git a/packages/machines/checkbox/src/checkbox.types.ts b/packages/machines/checkbox/src/checkbox.types.ts index b41e80e46f..d3be097554 100644 --- a/packages/machines/checkbox/src/checkbox.types.ts +++ b/packages/machines/checkbox/src/checkbox.types.ts @@ -28,27 +28,32 @@ interface PublicContext extends DirectionProperty, CommonProperties { */ ids?: ElementIds /** - * If `true`, the checkbox will be disabled + * Whether the checkbox is disabled */ disabled?: boolean /** - * If `true`, the checkbox is marked as invalid. + * Whether the checkbox is invalid */ invalid?: boolean /** - * If `true`, the checkbox input is marked as required, + * Whether the checkbox is required */ required?: boolean /** - * If `true`, the checkbox will be checked. + * The checked state of the checkbox */ checked: CheckedState /** - * The callback invoked when the checked state of the `Checkbox` changes. + * Whether the checkbox is read-only + */ + readOnly?: boolean + /** + * The callback invoked when the checked state changes. */ onCheckedChange?(details: CheckedChangeDetails): void /** - * The name of the input field in a checkbox. Useful for form submission. + * The name of the input field in a checkbox. + * Useful for form submission. */ name?: string /** @@ -120,19 +125,19 @@ export interface MachineApi { /** * Whether the checkbox is checked */ - isChecked: boolean + checked: boolean /** * Whether the checkbox is disabled */ - isDisabled: boolean | undefined + disabled: boolean | undefined /** * Whether the checkbox is indeterminate */ - isIndeterminate: boolean + indeterminate: boolean /** * Whether the checkbox is focused */ - isFocused: boolean | undefined + focused: boolean | undefined /** * The checked state of the checkbox */ diff --git a/packages/machines/clipboard/src/clipboard.connect.ts b/packages/machines/clipboard/src/clipboard.connect.ts index ed630cec6e..db267e5c61 100644 --- a/packages/machines/clipboard/src/clipboard.connect.ts +++ b/packages/machines/clipboard/src/clipboard.connect.ts @@ -5,10 +5,10 @@ import type { MachineApi, Send, State } from "./clipboard.types" import { dom } from "./clipboard.dom" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { - const isCopied = state.matches("copied") + const copied = state.matches("copied") return { - isCopied, + copied, value: state.context.value, setValue(value) { send({ type: "VALUE.SET", value }) @@ -18,23 +18,23 @@ export function connect(state: State, send: Send, normalize }, rootProps: normalize.element({ ...parts.root.attrs, - "data-copied": dataAttr(isCopied), + "data-copied": dataAttr(copied), id: dom.getRootId(state.context), }), labelProps: normalize.label({ ...parts.label.attrs, htmlFor: dom.getInputId(state.context), - "data-copied": dataAttr(isCopied), + "data-copied": dataAttr(copied), id: dom.getLabelId(state.context), }), controlProps: normalize.element({ ...parts.control.attrs, - "data-copied": dataAttr(isCopied), + "data-copied": dataAttr(copied), }), inputProps: normalize.input({ ...parts.input.attrs, defaultValue: state.context.value, - "data-copied": dataAttr(isCopied), + "data-copied": dataAttr(copied), readOnly: true, "data-readonly": "true", id: dom.getInputId(state.context), @@ -47,8 +47,8 @@ export function connect(state: State, send: Send, normalize }), triggerProps: normalize.button({ ...parts.trigger.attrs, - "aria-label": isCopied ? "Copied to clipboard" : "Copy to clipboard", - "data-copied": dataAttr(isCopied), + "aria-label": copied ? "Copied to clipboard" : "Copy to clipboard", + "data-copied": dataAttr(copied), onClick() { send({ type: "COPY" }) }, @@ -56,7 +56,7 @@ export function connect(state: State, send: Send, normalize getIndicatorProps(props) { return normalize.element({ ...parts.indicator.attrs, - hidden: props.copied !== isCopied, + hidden: props.copied !== copied, }) }, } diff --git a/packages/machines/clipboard/src/clipboard.types.ts b/packages/machines/clipboard/src/clipboard.types.ts index 89fb00c7c0..ad5c700061 100644 --- a/packages/machines/clipboard/src/clipboard.types.ts +++ b/packages/machines/clipboard/src/clipboard.types.ts @@ -58,7 +58,7 @@ export interface MachineApi { /** * Whether the value has been copied to the clipboard */ - isCopied: boolean + copied: boolean /** * The value to be copied to the clipboard */ diff --git a/packages/machines/collapsible/src/collapsible.connect.ts b/packages/machines/collapsible/src/collapsible.connect.ts index 7d2fcfd25d..7034c3daf5 100644 --- a/packages/machines/collapsible/src/collapsible.connect.ts +++ b/packages/machines/collapsible/src/collapsible.connect.ts @@ -5,39 +5,37 @@ import { dom } from "./collapsible.dom" import type { MachineApi, Send, State } from "./collapsible.types" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { - const isVisible = state.matches("open", "closing") - const isOpen = state.matches("open") + const visible = state.matches("open", "closing") + const open = state.matches("open") const height = state.context.height const width = state.context.width - const isDisabled = !!state.context.disabled + const disabled = !!state.context.disabled - const skipMountAnimation = state.context.isMountAnimationPrevented && isOpen + const skipMountAnimation = state.context.isMountAnimationPrevented && open return { - isDisabled, - isVisible, - isOpen, - open() { - send("OPEN") - }, - close() { - send("CLOSE") + disabled, + visible, + open, + setOpen(_open) { + if (_open === open) return + send(_open ? "OPEN" : "CLOSE") }, rootProps: normalize.element({ ...parts.root.attrs, - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", dir: state.context.dir, id: dom.getRootId(state.context), }), contentProps: normalize.element({ ...parts.content.attrs, - "data-state": skipMountAnimation ? undefined : isOpen ? "open" : "closed", + "data-state": skipMountAnimation ? undefined : open ? "open" : "closed", id: dom.getContentId(state.context), - "data-disabled": dataAttr(isDisabled), - hidden: !isVisible, + "data-disabled": dataAttr(disabled), + hidden: !visible, style: { "--height": height != null ? `${height}px` : undefined, "--width": width != null ? `${width}px` : undefined, @@ -49,13 +47,13 @@ export function connect(state: State, send: Send, normalize id: dom.getTriggerId(state.context), dir: state.context.dir, type: "button", - "data-state": isOpen ? "open" : "closed", - "data-disabled": dataAttr(isDisabled), + "data-state": open ? "open" : "closed", + "data-disabled": dataAttr(disabled), "aria-controls": dom.getContentId(state.context), - "aria-expanded": isVisible || false, + "aria-expanded": visible || false, onClick() { - if (isDisabled) return - send({ type: isOpen ? "CLOSE" : "OPEN", src: "trigger.click" }) + if (disabled) return + send({ type: open ? "CLOSE" : "OPEN", src: "trigger.click" }) }, }), } diff --git a/packages/machines/collapsible/src/collapsible.types.ts b/packages/machines/collapsible/src/collapsible.types.ts index 1534bcd502..a203963455 100644 --- a/packages/machines/collapsible/src/collapsible.types.ts +++ b/packages/machines/collapsible/src/collapsible.types.ts @@ -91,23 +91,20 @@ export interface MachineApi { /** * Whether the collapsible is open. */ - isOpen: boolean + open: boolean /** * Whether the collapsible is visible (open or closing) */ - isVisible: boolean + visible: boolean /** * Whether the collapsible is disabled */ - isDisabled: boolean - /** - * Function to open the collapsible. - */ - open(): void + disabled: boolean /** - * Function to close the collapsible. + * Function to open or close the collapsible. */ - close(): void + setOpen(open: boolean): void + rootProps: T["element"] triggerProps: T["button"] contentProps: T["element"] diff --git a/packages/machines/color-picker/package.json b/packages/machines/color-picker/package.json index d7a2811237..8905765bcc 100644 --- a/packages/machines/color-picker/package.json +++ b/packages/machines/color-picker/package.json @@ -44,7 +44,6 @@ "@zag-js/utils": "workspace:*", "@zag-js/form-utils": "workspace:*", "@zag-js/color-utils": "workspace:*", - "@zag-js/visually-hidden": "workspace:*", "@zag-js/popper": "workspace:*", "@zag-js/text-selection": "workspace:*", "@zag-js/types": "workspace:*" diff --git a/packages/machines/color-picker/src/color-picker.connect.ts b/packages/machines/color-picker/src/color-picker.connect.ts index f284442c8b..ad4988e790 100644 --- a/packages/machines/color-picker/src/color-picker.connect.ts +++ b/packages/machines/color-picker/src/color-picker.connect.ts @@ -8,10 +8,9 @@ import { isModifierKey, type EventKeyMap, } from "@zag-js/dom-event" -import { dataAttr, query } from "@zag-js/dom-query" +import { dataAttr, query, visuallyHiddenStyle } from "@zag-js/dom-query" import { getPlacementStyles } from "@zag-js/popper" import type { NormalizeProps, PropTypes } from "@zag-js/types" -import { visuallyHiddenStyle } from "@zag-js/visually-hidden" import { parts } from "./color-picker.anatomy" import { dom } from "./color-picker.dom" import type { @@ -32,12 +31,12 @@ export function connect(state: State, send: Send, normalize const areaValue = state.context.areaValue const valueAsString = state.context.valueAsString - const isDisabled = state.context.isDisabled - const isInteractive = state.context.isInteractive + const disabled = state.context.isDisabled + const interactive = state.context.isInteractive - const isDragging = state.hasTag("dragging") - const isOpen = state.hasTag("open") - const isFocused = state.hasTag("focused") + const dragging = state.hasTag("dragging") + const open = state.hasTag("open") + const focused = state.hasTag("focused") const getAreaChannels = (props: AreaProps) => { const channels = areaValue.getChannels() @@ -58,21 +57,19 @@ export function connect(state: State, send: Send, normalize return { value: color, valueAsString: color.toString("hex"), - isChecked: color.isEqual(value), - isDisabled: props.disabled || !isInteractive, + checked: color.isEqual(value), + disabled: props.disabled || !interactive, } } return { - isDragging, - isOpen, + dragging, + open, valueAsString, value, - open() { - send({ type: "OPEN" }) - }, - close() { - send({ type: "CLOSE" }) + setOpen(_open) { + if (_open === open) return + send({ type: _open ? "OPEN" : "CLOSE" }) }, setValue(value) { send({ type: "VALUE.SET", value: normalizeColor(value), src: "set-color" }) @@ -99,7 +96,7 @@ export function connect(state: State, send: Send, normalize ...parts.root.attrs, dir: state.context.dir, id: dom.getRootId(state.context), - "data-disabled": dataAttr(isDisabled), + "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(state.context.readOnly), style: { "--value": value.toString("css"), @@ -111,9 +108,9 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, id: dom.getLabelId(state.context), htmlFor: dom.getHiddenInputId(state.context), - "data-disabled": dataAttr(isDisabled), + "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(state.context.readOnly), - "data-focus": dataAttr(isFocused), + "data-focus": dataAttr(focused), onClick(event) { event.preventDefault() const inputEl = query(dom.getControlEl(state.context), "[data-channel=hex]") @@ -125,33 +122,33 @@ export function connect(state: State, send: Send, normalize ...parts.control.attrs, id: dom.getControlId(state.context), dir: state.context.dir, - "data-disabled": dataAttr(isDisabled), + "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(state.context.readOnly), - "data-state": isOpen ? "open" : "closed", - "data-focus": dataAttr(isFocused), + "data-state": open ? "open" : "closed", + "data-focus": dataAttr(focused), }), triggerProps: normalize.button({ ...parts.trigger.attrs, id: dom.getTriggerId(state.context), dir: state.context.dir, - disabled: isDisabled, + disabled: disabled, "aria-label": `select color. current color is ${valueAsString}`, "aria-controls": dom.getContentId(state.context), "aria-labelledby": dom.getLabelId(state.context), - "data-disabled": dataAttr(isDisabled), + "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(state.context.readOnly), "data-placement": currentPlacement, - "aria-expanded": dataAttr(isOpen), - "data-state": isOpen ? "open" : "closed", - "data-focus": dataAttr(isFocused), + "aria-expanded": dataAttr(open), + "data-state": open ? "open" : "closed", + "data-focus": dataAttr(focused), type: "button", onClick() { - if (!isInteractive) return + if (!interactive) return send({ type: "TRIGGER.CLICK" }) }, onBlur() { - if (!isInteractive) return + if (!interactive) return send({ type: "TRIGGER.BLUR" }) }, style: { @@ -171,8 +168,8 @@ export function connect(state: State, send: Send, normalize id: dom.getContentId(state.context), dir: state.context.dir, "data-placement": currentPlacement, - "data-state": isOpen ? "open" : "closed", - hidden: !isOpen, + "data-state": open ? "open" : "closed", + hidden: !open, }), getAreaProps(props = {}) { @@ -188,7 +185,7 @@ export function connect(state: State, send: Send, normalize id: dom.getAreaId(state.context), role: "group", onPointerDown(event) { - if (!isInteractive) return + if (!interactive) return const evt = getNativeEvent(event) if (!isLeftClick(evt) || isModifierKey(evt)) return @@ -242,8 +239,8 @@ export function connect(state: State, send: Send, normalize ...parts.areaThumb.attrs, id: dom.getAreaThumbId(state.context), dir: state.context.dir, - tabIndex: isDisabled ? undefined : 0, - "data-disabled": dataAttr(isDisabled), + tabIndex: disabled ? undefined : 0, + "data-disabled": dataAttr(disabled), role: "slider", "aria-valuemin": 0, "aria-valuemax": 100, @@ -261,12 +258,12 @@ export function connect(state: State, send: Send, normalize background: areaValue.withChannelValue("alpha", 1).toString("css"), }, onFocus() { - if (!isInteractive) return + if (!interactive) return send({ type: "AREA.FOCUS", id: "area", channel }) }, onKeyDown(event) { if (event.defaultPrevented) return - if (!isInteractive) return + if (!interactive) return const step = getEventStep(event) @@ -331,7 +328,7 @@ export function connect(state: State, send: Send, normalize "data-orientation": orientation, role: "presentation", onPointerDown(event) { - if (!isInteractive) return + if (!interactive) return const evt = getNativeEvent(event) if (!isLeftClick(evt) || isModifierKey(evt)) return @@ -387,11 +384,11 @@ export function connect(state: State, send: Send, normalize id: dom.getChannelSliderThumbId(state.context, channel), role: "slider", "aria-label": channel, - tabIndex: isDisabled ? undefined : 0, + tabIndex: disabled ? undefined : 0, "data-channel": channel, - "data-disabled": dataAttr(isDisabled), + "data-disabled": dataAttr(disabled), "data-orientation": orientation, - "aria-disabled": dataAttr(isDisabled), + "aria-disabled": dataAttr(disabled), "aria-orientation": orientation, "aria-valuemax": maxValue, "aria-valuemin": minValue, @@ -404,12 +401,12 @@ export function connect(state: State, send: Send, normalize ...placementStyles, }, onFocus() { - if (!isInteractive) return + if (!interactive) return send({ type: "CHANNEL_SLIDER.FOCUS", channel }) }, onKeyDown(event) { if (event.defaultPrevented) return - if (!isInteractive) return + if (!interactive) return const step = getEventStep(event) * stepValue @@ -466,33 +463,33 @@ export function connect(state: State, send: Send, normalize "aria-label": channel, spellCheck: false, autoComplete: "off", - disabled: isDisabled, - "data-disabled": dataAttr(isDisabled), + disabled: disabled, + "data-disabled": dataAttr(disabled), readOnly: state.context.readOnly, defaultValue: getChannelValue(value, channel), min: range?.minValue, max: range?.maxValue, step: range?.step, onBeforeInput(event) { - if (isTextField || !isInteractive) return + if (isTextField || !interactive) return const value = event.currentTarget.value if (value.match(/[^0-9.]/g)) { event.preventDefault() } }, onFocus(event) { - if (!isInteractive) return + if (!interactive) return send({ type: "CHANNEL_INPUT.FOCUS", channel }) event.target.select() }, onBlur(event) { - if (!isInteractive) return + if (!interactive) return const value = isTextField ? event.currentTarget.value : event.currentTarget.valueAsNumber send({ type: "CHANNEL_INPUT.BLUR", channel, value, isTextField }) }, onKeyDown(event) { if (event.defaultPrevented) return - if (!isInteractive) return + if (!interactive) return if (event.key === "Enter") { const value = isTextField ? event.currentTarget.value : event.currentTarget.valueAsNumber send({ type: "CHANNEL_INPUT.CHANGE", channel, value, isTextField }) @@ -509,7 +506,7 @@ export function connect(state: State, send: Send, normalize hiddenInputProps: normalize.input({ type: "text", - disabled: isDisabled, + disabled: disabled, name: state.context.name, id: dom.getHiddenInputId(state.context), style: visuallyHiddenStyle, @@ -520,11 +517,11 @@ export function connect(state: State, send: Send, normalize ...parts.eyeDropperTrigger.attrs, type: "button", dir: state.context.dir, - disabled: isDisabled, - "data-disabled": dataAttr(isDisabled), + disabled: disabled, + "data-disabled": dataAttr(disabled), "aria-label": "Pick a color from the screen", onClick() { - if (!isInteractive) return + if (!interactive) return send("EYEDROPPER.CLICK") }, }), @@ -540,15 +537,15 @@ export function connect(state: State, send: Send, normalize const triggerState = getSwatchTriggerState(props) return normalize.button({ ...parts.swatchTrigger.attrs, - disabled: triggerState.isDisabled, + disabled: triggerState.disabled, dir: state.context.dir, type: "button", "aria-label": `select ${triggerState.valueAsString} as the color`, - "data-state": triggerState.isChecked ? "checked" : "unchecked", + "data-state": triggerState.checked ? "checked" : "unchecked", "data-value": triggerState.valueAsString, - "data-disabled": dataAttr(triggerState.isDisabled), + "data-disabled": dataAttr(triggerState.disabled), onClick() { - if (triggerState.isDisabled) return + if (triggerState.disabled) return send({ type: "SWATCH_TRIGGER.CLICK", value: triggerState.value }) }, style: { @@ -562,7 +559,7 @@ export function connect(state: State, send: Send, normalize return normalize.element({ ...parts.swatchIndicator.attrs, dir: state.context.dir, - hidden: !triggerState.isChecked, + hidden: !triggerState.checked, }) }, @@ -572,7 +569,7 @@ export function connect(state: State, send: Send, normalize return normalize.element({ ...parts.swatch.attrs, dir: state.context.dir, - "data-state": triggerState.isChecked ? "checked" : "unchecked", + "data-state": triggerState.checked ? "checked" : "unchecked", "data-value": triggerState.valueAsString, style: { position: "relative", @@ -598,7 +595,7 @@ export function connect(state: State, send: Send, normalize "aria-label": "change color format", dir: state.context.dir, defaultValue: state.context.format, - disabled: isDisabled, + disabled: disabled, onChange(event) { const format = assertFormat(event.currentTarget.value) send({ type: "FORMAT.SET", format, src: "format-select" }) diff --git a/packages/machines/color-picker/src/color-picker.machine.ts b/packages/machines/color-picker/src/color-picker.machine.ts index b0a1d271fa..4bb0f1a20f 100644 --- a/packages/machines/color-picker/src/color-picker.machine.ts +++ b/packages/machines/color-picker/src/color-picker.machine.ts @@ -404,11 +404,11 @@ export function machine(userContext: UserDefinedContext) { openEyeDropper(ctx) { const isSupported = "EyeDropper" in dom.getWin(ctx) if (!isSupported) return - const win = dom.getWin(ctx) as any + const win = dom.getWin(ctx) const picker = new win.EyeDropper() picker .open() - .then(({ sRGBHex }: { sRGBHex: string }) => { + .then(({ sRGBHex }) => { const format = ctx.value.getFormat() const color = parseColor(sRGBHex).toFormat(format) as Color set.value(ctx, color) diff --git a/packages/machines/color-picker/src/color-picker.types.ts b/packages/machines/color-picker/src/color-picker.types.ts index d01e222427..c6dd65a700 100644 --- a/packages/machines/color-picker/src/color-picker.types.ts +++ b/packages/machines/color-picker/src/color-picker.types.ts @@ -7,6 +7,20 @@ import type { MaybeFunction } from "@zag-js/utils" export type ExtendedColorChannel = ColorChannel | "hex" | "css" +// patch the global window object to include the EyeDropper API + +interface EyeDropper { + new (): EyeDropper + open: (options?: { signal?: AbortSignal }) => Promise<{ sRGBHex: string }> + [Symbol.toStringTag]: "EyeDropper" +} + +declare global { + interface Window { + EyeDropper: EyeDropper + } +} + /* ----------------------------------------------------------------------------- * Callback details * -----------------------------------------------------------------------------*/ @@ -218,8 +232,8 @@ export interface SwatchTriggerProps { export interface SwatchTriggerState { value: Color valueAsString: string - isChecked: boolean - isDisabled: boolean + checked: boolean + disabled: boolean } export interface SwatchProps { @@ -241,11 +255,11 @@ export interface MachineApi { /** * Whether the color picker is being dragged */ - isDragging: boolean + dragging: boolean /** * Whether the color picker is open */ - isOpen: boolean + open: boolean /** * The current color value (as a string) */ @@ -283,13 +297,9 @@ export interface MachineApi { */ setAlpha(value: number): void /** - * Function to open the color picker - */ - open(): void - /** - * Function to close the color picker + * Function to open or close the color picker */ - close(): void + setOpen(open: boolean): void rootProps: T["element"] labelProps: T["element"] diff --git a/packages/machines/combobox/src/combobox.connect.ts b/packages/machines/combobox/src/combobox.connect.ts index c698c343e7..56bea6054a 100644 --- a/packages/machines/combobox/src/combobox.connect.ts +++ b/packages/machines/combobox/src/combobox.connect.ts @@ -11,7 +11,7 @@ import { getPlacementStyles } from "@zag-js/popper" import type { NormalizeProps, PropTypes } from "@zag-js/types" import { parts } from "./combobox.anatomy" import { dom } from "./combobox.dom" -import type { CollectionItem, ItemProps, MachineApi, Send, State } from "./combobox.types" +import type { CollectionItem, ItemProps, ItemState, MachineApi, Send, State } from "./combobox.types" export function connect( state: State, @@ -21,13 +21,13 @@ export function connect( const translations = state.context.translations const collection = state.context.collection - const isDisabled = state.context.disabled - const isInteractive = state.context.isInteractive - const isInvalid = state.context.invalid - const isReadOnly = state.context.readOnly + const disabled = state.context.disabled + const interactive = state.context.isInteractive + const invalid = state.context.invalid + const readOnly = state.context.readOnly - const isOpen = state.hasTag("open") - const isFocused = state.hasTag("focused") + const open = state.hasTag("open") + const focused = state.hasTag("focused") const isDialogPopup = state.context.popup === "dialog" const popperStyles = getPlacementStyles({ @@ -35,23 +35,23 @@ export function connect( placement: state.context.currentPlacement, }) - function getItemState(props: ItemProps) { + function getItemState(props: ItemProps): ItemState { const { item } = props const disabled = collection.isItemDisabled(item) const value = collection.itemToValue(item) return { value, - isDisabled: Boolean(disabled || isDisabled), - isHighlighted: state.context.highlightedValue === value, - isSelected: state.context.value.includes(value), + disabled: Boolean(disabled || disabled), + highlighted: state.context.highlightedValue === value, + selected: state.context.value.includes(value), } } return { - isFocused, - isOpen, + focused, + open, inputValue: state.context.inputValue, - isInputValueEmpty: state.context.isInputValueEmpty, + inputEmpty: state.context.isInputValueEmpty, highlightedValue: state.context.highlightedValue, highlightedItem: state.context.highlightedItem, value: state.context.value, @@ -87,21 +87,16 @@ export function connect( focus() { dom.getInputEl(state.context)?.focus() }, - open() { - if (isOpen) return - send("OPEN") + setOpen(_open) { + if (_open === open) return + send(_open ? "OPEN" : "CLOSE") }, - close() { - if (!isOpen) return - send("CLOSE") - }, - rootProps: normalize.element({ ...parts.root.attrs, dir: state.context.dir, id: dom.getRootId(state.context), - "data-invalid": dataAttr(isInvalid), - "data-readonly": dataAttr(isReadOnly), + "data-invalid": dataAttr(invalid), + "data-readonly": dataAttr(readOnly), }), labelProps: normalize.label({ @@ -109,10 +104,10 @@ export function connect( dir: state.context.dir, htmlFor: dom.getInputId(state.context), id: dom.getLabelId(state.context), - "data-readonly": dataAttr(isReadOnly), - "data-disabled": dataAttr(isDisabled), - "data-invalid": dataAttr(isInvalid), - "data-focus": dataAttr(isFocused), + "data-readonly": dataAttr(readOnly), + "data-disabled": dataAttr(disabled), + "data-invalid": dataAttr(invalid), + "data-focus": dataAttr(focused), onClick(event) { if (!isDialogPopup) return event.preventDefault() @@ -124,10 +119,10 @@ export function connect( ...parts.control.attrs, dir: state.context.dir, id: dom.getControlId(state.context), - "data-state": isOpen ? "open" : "closed", - "data-focus": dataAttr(isFocused), - "data-disabled": dataAttr(isDisabled), - "data-invalid": dataAttr(isInvalid), + "data-state": open ? "open" : "closed", + "data-focus": dataAttr(focused), + "data-disabled": dataAttr(disabled), + "data-invalid": dataAttr(invalid), }), positionerProps: normalize.element({ @@ -140,17 +135,17 @@ export function connect( inputProps: normalize.input({ ...parts.input.attrs, dir: state.context.dir, - "aria-invalid": ariaAttr(isInvalid), - "data-invalid": dataAttr(isInvalid), + "aria-invalid": ariaAttr(invalid), + "data-invalid": dataAttr(invalid), name: state.context.name, form: state.context.form, - disabled: isDisabled, + disabled: disabled, autoFocus: state.context.autoFocus, autoComplete: "off", autoCorrect: "off", autoCapitalize: "none", spellCheck: "false", - readOnly: isReadOnly, + readOnly: readOnly, placeholder: state.context.placeholder, id: dom.getInputId(state.context), type: "text", @@ -158,22 +153,22 @@ export function connect( defaultValue: state.context.inputValue, "aria-autocomplete": state.context.autoComplete ? "both" : "list", "aria-controls": isDialogPopup ? dom.getListId(state.context) : dom.getContentId(state.context), - "aria-expanded": isOpen, - "data-state": isOpen ? "open" : "closed", + "aria-expanded": open, + "data-state": open ? "open" : "closed", "aria-activedescendant": state.context.highlightedValue ? dom.getItemId(state.context, state.context.highlightedValue) : undefined, onClick() { if (!state.context.openOnClick) return - if (!isInteractive) return + if (!interactive) return send("INPUT.CLICK") }, onFocus() { - if (isDisabled) return + if (disabled) return send("INPUT.FOCUS") }, onBlur() { - if (isDisabled) return + if (disabled) return send("INPUT.BLUR") }, onChange(event) { @@ -181,7 +176,7 @@ export function connect( }, onKeyDown(event) { if (event.defaultPrevented) return - if (!isInteractive) return + if (!interactive) return const evt = getNativeEvent(event) if (evt.ctrlKey || evt.shiftKey || evt.isComposing) return @@ -192,33 +187,33 @@ export function connect( const keymap: EventKeyMap = { ArrowDown(event) { - if (!openOnKeyPress && !isOpen) return + if (!openOnKeyPress && !open) return send({ type: event.altKey ? "OPEN" : "INPUT.ARROW_DOWN", keypress }) event.preventDefault() }, ArrowUp() { - if (!openOnKeyPress && !isOpen) return + if (!openOnKeyPress && !open) return send({ type: event.altKey ? "CLOSE" : "INPUT.ARROW_UP", keypress }) event.preventDefault() }, Home(event) { if (isModifierKey) return send({ type: "INPUT.HOME", keypress }) - if (isOpen) { + if (open) { event.preventDefault() } }, End(event) { if (isModifierKey) return send({ type: "INPUT.END", keypress }) - if (isOpen) { + if (open) { event.preventDefault() } }, Enter(event) { if (evt.isComposing) return send({ type: "INPUT.ENTER", keypress }) - if (isOpen) { + if (open) { event.preventDefault() } const itemEl = dom.getHighlightedItemEl(state.context) @@ -244,20 +239,20 @@ export function connect( type: "button", tabIndex: isDialogPopup ? 0 : -1, "aria-label": translations.triggerLabel, - "aria-expanded": isOpen, - "data-state": isOpen ? "open" : "closed", - "aria-controls": isOpen ? dom.getContentId(state.context) : undefined, - disabled: isDisabled, - "data-readonly": dataAttr(isReadOnly), - "data-disabled": dataAttr(isDisabled), + "aria-expanded": open, + "data-state": open ? "open" : "closed", + "aria-controls": open ? dom.getContentId(state.context) : undefined, + disabled: disabled, + "data-readonly": dataAttr(readOnly), + "data-disabled": dataAttr(disabled), onClick(event) { const evt = getNativeEvent(event) - if (!isInteractive) return + if (!interactive) return if (!isLeftClick(evt)) return send("TRIGGER.CLICK") }, onPointerDown(event) { - if (!isInteractive) return + if (!interactive) return if (event.pointerType === "touch") return event.preventDefault() queueMicrotask(() => { @@ -301,8 +296,8 @@ export function connect( id: dom.getContentId(state.context), role: isDialogPopup ? "dialog" : "listbox", tabIndex: -1, - hidden: !isOpen, - "data-state": isOpen ? "open" : "closed", + hidden: !open, + "data-state": open ? "open" : "closed", "aria-labelledby": dom.getLabelId(state.context), "aria-multiselectable": state.context.multiple && !isDialogPopup ? true : undefined, onPointerDown(event) { @@ -324,12 +319,12 @@ export function connect( id: dom.getClearTriggerId(state.context), type: "button", tabIndex: -1, - disabled: isDisabled, + disabled: disabled, "aria-label": translations.clearTriggerLabel, "aria-controls": dom.getInputId(state.context), hidden: !state.context.value.length, onClick() { - if (!isInteractive) return + if (!interactive) return send({ type: "VALUE.CLEAR", src: "clear-trigger" }) }, }), @@ -346,19 +341,19 @@ export function connect( id: dom.getItemId(state.context, value), role: "option", tabIndex: -1, - "data-highlighted": dataAttr(itemState.isHighlighted), - "data-state": itemState.isSelected ? "checked" : "unchecked", - "aria-selected": itemState.isHighlighted, - "aria-disabled": itemState.isDisabled, - "data-disabled": dataAttr(itemState.isDisabled), + "data-highlighted": dataAttr(itemState.highlighted), + "data-state": itemState.selected ? "checked" : "unchecked", + "aria-selected": itemState.highlighted, + "aria-disabled": itemState.disabled, + "data-disabled": dataAttr(itemState.disabled), "data-value": itemState.value, onPointerMove() { - if (itemState.isDisabled) return + if (itemState.disabled) return send({ type: "ITEM.POINTER_MOVE", value }) }, onPointerLeave() { if (props.persistFocus) return - if (itemState.isDisabled) return + if (itemState.disabled) return const mouseMoved = state.previousEvent.type === "ITEM.POINTER_MOVE" if (!mouseMoved) return send({ type: "ITEM.POINTER_LEAVE", value }) @@ -367,7 +362,7 @@ export function connect( if (isDownloadingEvent(event)) return if (isOpeningInNewTab(event)) return if (isContextMenuEvent(event)) return - if (itemState.isDisabled) return + if (itemState.disabled) return send({ type: "ITEM.CLICK", src: "pointerup", value }) }, onTouchEnd(event) { @@ -383,8 +378,8 @@ export function connect( return normalize.element({ ...parts.itemText.attrs, dir: state.context.dir, - "data-disabled": dataAttr(itemState.isDisabled), - "data-highlighted": dataAttr(itemState.isHighlighted), + "data-disabled": dataAttr(itemState.disabled), + "data-highlighted": dataAttr(itemState.highlighted), }) }, getItemIndicatorProps(props) { @@ -393,8 +388,8 @@ export function connect( "aria-hidden": true, ...parts.itemIndicator.attrs, dir: state.context.dir, - "data-state": itemState.isSelected ? "checked" : "unchecked", - hidden: !itemState.isSelected, + "data-state": itemState.selected ? "checked" : "unchecked", + hidden: !itemState.selected, }) }, diff --git a/packages/machines/combobox/src/combobox.types.ts b/packages/machines/combobox/src/combobox.types.ts index 6bd495fac1..858b85e86c 100644 --- a/packages/machines/combobox/src/combobox.types.ts +++ b/packages/machines/combobox/src/combobox.types.ts @@ -278,15 +278,33 @@ export type Send = S.Send * -----------------------------------------------------------------------------*/ export interface ItemProps { + /** + * Whether hovering outside should clear the highlighted state + */ persistFocus?: boolean + /** + * The item to render + */ item: CollectionItem } export interface ItemState { + /** + * The value of the item + */ value: string - isDisabled: boolean - isSelected: boolean - isHighlighted: boolean + /** + * Whether the item is disabled + */ + disabled: boolean + /** + * Whether the item is selected + */ + selected: boolean + /** + * Whether the item is highlighted via pointer or keyboard navigation + */ + highlighted: boolean } export interface ItemGroupProps { @@ -301,15 +319,15 @@ export interface MachineApi(state: State, send: Send, normalize const disabled = state.context.disabled const readOnly = state.context.readOnly - const isInteractive = state.context.isInteractive + const interactive = state.context.isInteractive const min = state.context.min const max = state.context.max @@ -71,8 +71,8 @@ export function connect(state: State, send: Send, normalize const timeZone = state.context.timeZone const startOfWeek = state.context.startOfWeek - const isFocused = state.matches("focused") - const isOpen = state.matches("open") + const focused = state.matches("focused") + const open = state.matches("open") const isRangePicker = state.context.selectionMode === "range" const isDateUnavailableFn = state.context.isDateUnavailable @@ -120,12 +120,12 @@ export function connect(state: State, send: Send, normalize const { value, disabled } = props const normalized = focusedValue.set({ year: value }) const cellState = { - isFocused: focusedValue.year === props.value, - isSelectable: !isDateInvalid(normalized, min, max), - isSelected: !!selectedValue.find((date) => date.year === value), + focused: focusedValue.year === props.value, + selectable: !isDateInvalid(normalized, min, max), + selected: !!selectedValue.find((date) => date.year === value), valueText: value.toString(), - get isDisabled() { - return disabled || !cellState.isSelectable + get disabled() { + return disabled || !cellState.selectable }, } return cellState @@ -136,12 +136,12 @@ export function connect(state: State, send: Send, normalize const normalized = focusedValue.set({ month: value }) const formatter = getMonthFormatter(locale, timeZone) const cellState = { - isFocused: focusedValue.month === props.value, - isSelectable: !isDateInvalid(normalized, min, max), - isSelected: !!selectedValue.find((date) => date.month === value && date.year === focusedValue.year), + focused: focusedValue.month === props.value, + selectable: !isDateInvalid(normalized, min, max), + selected: !!selectedValue.find((date) => date.month === value && date.year === focusedValue.year), valueText: formatter.format(normalized.toDate(timeZone)), - get isDisabled() { - return disabled || !cellState.isSelectable + get disabled() { + return disabled || !cellState.selectable }, } return cellState @@ -156,28 +156,28 @@ export function connect(state: State, send: Send, normalize const end = visibleRange.start.add(unitDuration).subtract({ days: 1 }) const cellState = { - isInvalid: isDateInvalid(value, min, max), - isDisabled: disabled || isDateDisabled(value, visibleRange.start, end, min, max), - isSelected: selectedValue.some((date) => isDateEqual(value, date)), - isUnavailable: isDateUnavailable(value, isDateUnavailableFn, locale, min, max) && !disabled, - isOutsideRange: isDateOutsideVisibleRange(value, visibleRange.start, end), - isInRange: + invalid: isDateInvalid(value, min, max), + disabled: disabled || isDateDisabled(value, visibleRange.start, end, min, max), + selected: selectedValue.some((date) => isDateEqual(value, date)), + unavailable: isDateUnavailable(value, isDateUnavailableFn, locale, min, max) && !disabled, + outsideRange: isDateOutsideVisibleRange(value, visibleRange.start, end), + inRange: isRangePicker && (isDateWithinRange(value, selectedValue) || isDateWithinRange(value, hoveredRangeValue)), - isFirstInRange: isRangePicker && isDateEqual(value, selectedValue[0]), - isLastInRange: isRangePicker && isDateEqual(value, selectedValue[1]), - isToday: isTodayDate(value, timeZone), - isWeekend: isWeekend(value, locale), + firstInRange: isRangePicker && isDateEqual(value, selectedValue[0]), + lastInRange: isRangePicker && isDateEqual(value, selectedValue[1]), + today: isTodayDate(value, timeZone), + weekend: isWeekend(value, locale), formattedDate: formatter.format(value.toDate(timeZone)), - get isFocused() { - return isDateEqual(value, focusedValue) && !cellState.isOutsideRange + get focused() { + return isDateEqual(value, focusedValue) && !cellState.outsideRange }, get ariaLabel() { - if (cellState.isUnavailable) return `Not available. ${cellState.formattedDate}` - if (cellState.isSelected) return `Selected date. ${cellState.formattedDate}` + if (cellState.unavailable) return `Not available. ${cellState.formattedDate}` + if (cellState.selected) return `Selected date. ${cellState.formattedDate}` return `Choose ${cellState.formattedDate}` }, - get isSelectable() { - return !cellState.isDisabled && !cellState.isUnavailable + get selectable() { + return !cellState.disabled && !cellState.unavailable }, } return cellState @@ -189,8 +189,8 @@ export function connect(state: State, send: Send, normalize } return { - isFocused, - isOpen, + focused, + open, view: state.context.view, getRangePresetValue(preset) { return getDateRangePreset(preset, locale, timeZone) @@ -231,11 +231,9 @@ export function connect(state: State, send: Send, normalize setFocusedValue(value) { send({ type: "FOCUS.SET", value }) }, - open() { - send("OPEN") - }, - close() { - send("CLOSE") + setOpen(_open) { + if (_open === open) return + send(_open ? "OPEN" : "CLOSE") }, focusMonth, focusYear, @@ -270,7 +268,7 @@ export function connect(state: State, send: Send, normalize ...parts.root.attrs, dir: state.context.dir, id: dom.getRootId(state.context), - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(readOnly), }), @@ -279,7 +277,7 @@ export function connect(state: State, send: Send, normalize ...parts.label.attrs, dir: state.context.dir, htmlFor: dom.getInputId(state.context, 0), - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(readOnly), }), @@ -298,9 +296,9 @@ export function connect(state: State, send: Send, normalize contentProps: normalize.element({ ...parts.content.attrs, - hidden: !isOpen, + hidden: !open, dir: state.context.dir, - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", "data-placement": currentPlacement, id: dom.getContentId(state.context), role: "application", @@ -425,10 +423,10 @@ export function connect(state: State, send: Send, normalize return normalize.element({ ...parts.tableCell.attrs, role: "gridcell", - "aria-disabled": ariaAttr(!cellState.isSelectable), - "aria-selected": cellState.isSelected || cellState.isInRange, - "aria-invalid": ariaAttr(cellState.isInvalid), - "aria-current": cellState.isToday ? "date" : undefined, + "aria-disabled": ariaAttr(!cellState.selectable), + "aria-selected": cellState.selected || cellState.inRange, + "aria-invalid": ariaAttr(cellState.invalid), + "aria-current": cellState.today ? "date" : undefined, "data-value": value.toString(), }) }, @@ -440,28 +438,29 @@ export function connect(state: State, send: Send, normalize id: dom.getCellTriggerId(state.context, value.toString()), role: "button", dir: state.context.dir, - tabIndex: cellState.isFocused ? 0 : -1, + tabIndex: cellState.focused ? 0 : -1, "aria-label": cellState.ariaLabel, - "aria-disabled": ariaAttr(!cellState.isSelectable), - "aria-invalid": ariaAttr(cellState.isInvalid), - "data-disabled": dataAttr(!cellState.isSelectable), - "data-selected": dataAttr(cellState.isSelected), + "aria-disabled": ariaAttr(!cellState.selectable), + "aria-invalid": ariaAttr(cellState.invalid), + "data-disabled": dataAttr(!cellState.selectable), + "data-selected": dataAttr(cellState.selected), "data-value": value.toString(), "data-view": "day", - "data-today": dataAttr(cellState.isToday), - "data-focused": dataAttr(cellState.isFocused), - "data-unavailable": dataAttr(cellState.isUnavailable), - "data-range-start": dataAttr(cellState.isFirstInRange), - "data-range-end": dataAttr(cellState.isLastInRange), - "data-in-range": dataAttr(cellState.isInRange), - "data-outside-range": dataAttr(cellState.isOutsideRange), - "data-weekend": dataAttr(cellState.isWeekend), - onClick() { - if (!cellState.isSelectable) return + "data-today": dataAttr(cellState.today), + "data-focused": dataAttr(cellState.focused), + "data-unavailable": dataAttr(cellState.unavailable), + "data-range-start": dataAttr(cellState.firstInRange), + "data-range-end": dataAttr(cellState.lastInRange), + "data-in-range": dataAttr(cellState.inRange), + "data-outside-range": dataAttr(cellState.outsideRange), + "data-weekend": dataAttr(cellState.weekend), + onClick(event) { + if (event.defaultPrevented) return + if (!cellState.selectable) return send({ type: "CELL.CLICK", cell: "day", value }) }, onPointerMove(event) { - if (event.pointerType === "touch" || !cellState.isSelectable) return + if (event.pointerType === "touch" || !cellState.selectable) return const focus = event.currentTarget.ownerDocument.activeElement !== event.currentTarget if (hoveredValue && isEqualDay(value, hoveredValue)) return send({ type: "CELL.POINTER_MOVE", cell: "day", value, focus }) @@ -478,9 +477,9 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, colSpan: columns, role: "gridcell", - "aria-selected": ariaAttr(cellState.isSelected), - "data-selected": dataAttr(cellState.isSelected), - "aria-disabled": ariaAttr(!cellState.isSelectable), + "aria-selected": ariaAttr(cellState.selected), + "data-selected": dataAttr(cellState.selected), + "aria-disabled": ariaAttr(!cellState.selectable), "data-value": value, }) }, @@ -492,16 +491,17 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, role: "button", id: dom.getCellTriggerId(state.context, value.toString()), - "data-selected": dataAttr(cellState.isSelected), - "aria-disabled": ariaAttr(!cellState.isSelectable), - "data-disabled": dataAttr(!cellState.isSelectable), - "data-focused": dataAttr(cellState.isFocused), + "data-selected": dataAttr(cellState.selected), + "aria-disabled": ariaAttr(!cellState.selectable), + "data-disabled": dataAttr(!cellState.selectable), + "data-focused": dataAttr(cellState.focused), "aria-label": cellState.valueText, "data-view": "month", "data-value": value, - tabIndex: cellState.isFocused ? 0 : -1, - onClick() { - if (!cellState.isSelectable) return + tabIndex: cellState.focused ? 0 : -1, + onClick(event) { + if (event.defaultPrevented) return + if (!cellState.selectable) return send({ type: "CELL.CLICK", cell: "month", value }) }, }) @@ -516,9 +516,9 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, colSpan: columns, role: "gridcell", - "aria-selected": ariaAttr(cellState.isSelected), - "data-selected": dataAttr(cellState.isSelected), - "aria-disabled": ariaAttr(!cellState.isSelectable), + "aria-selected": ariaAttr(cellState.selected), + "data-selected": dataAttr(cellState.selected), + "aria-disabled": ariaAttr(!cellState.selectable), "data-value": value, }) }, @@ -530,16 +530,17 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, role: "button", id: dom.getCellTriggerId(state.context, value.toString()), - "data-selected": dataAttr(cellState.isSelected), - "data-focused": dataAttr(cellState.isFocused), - "aria-disabled": ariaAttr(!cellState.isSelectable), - "data-disabled": dataAttr(!cellState.isSelectable), + "data-selected": dataAttr(cellState.selected), + "data-focused": dataAttr(cellState.focused), + "aria-disabled": ariaAttr(!cellState.selectable), + "data-disabled": dataAttr(!cellState.selectable), "aria-label": cellState.valueText, "data-value": value, "data-view": "year", - tabIndex: cellState.isFocused ? 0 : -1, - onClick() { - if (!cellState.isSelectable) return + tabIndex: cellState.focused ? 0 : -1, + onClick(event) { + if (event.defaultPrevented) return + if (!cellState.selectable) return send({ type: "CELL.CLICK", cell: "year", value }) }, }) @@ -554,7 +555,8 @@ export function connect(state: State, send: Send, normalize type: "button", "aria-label": getNextTriggerLabel(view), disabled: disabled || !state.context.isNextVisibleRangeValid, - onClick() { + onClick(event) { + if (event.defaultPrevented) return send({ type: "GOTO.NEXT", view }) }, }) @@ -569,7 +571,8 @@ export function connect(state: State, send: Send, normalize type: "button", "aria-label": getPrevTriggerLabel(view), disabled: disabled || !state.context.isPrevVisibleRangeValid, - onClick() { + onClick(event) { + if (event.defaultPrevented) return send({ type: "GOTO.PREV", view }) }, }) @@ -582,7 +585,8 @@ export function connect(state: State, send: Send, normalize type: "button", "aria-label": "Clear dates", hidden: !state.context.value.length, - onClick() { + onClick(event) { + if (event.defaultPrevented) return send("VALUE.CLEAR") }, }), @@ -593,13 +597,14 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, type: "button", "data-placement": currentPlacement, - "aria-label": isOpen ? "Close calendar" : "Open calendar", + "aria-label": open ? "Close calendar" : "Open calendar", "aria-controls": dom.getContentId(state.context), - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", "aria-haspopup": "grid", disabled, - onClick() { - if (!isInteractive) return + onClick(event) { + if (event.defaultPrevented) return + if (!interactive) return send("TRIGGER.CLICK") }, }), @@ -614,8 +619,9 @@ export function connect(state: State, send: Send, normalize type: "button", disabled, "aria-label": getViewTriggerLabel(state.context.view), - onClick() { - if (!isInteractive) return + onClick(event) { + if (event.defaultPrevented) return + if (!interactive) return send("VIEW.CHANGE") }, }) @@ -641,7 +647,7 @@ export function connect(state: State, send: Send, normalize spellCheck: "false", dir: state.context.dir, name: state.context.name, - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", readOnly, disabled, placeholder: getInputPlaceholder(locale), @@ -660,7 +666,7 @@ export function connect(state: State, send: Send, normalize }, onKeyDown(event) { if (event.defaultPrevented) return - if (!isInteractive) return + if (!interactive) return const evt = getNativeEvent(event) if (evt.isComposing) return if (event.key !== "Enter") return @@ -714,7 +720,8 @@ export function connect(state: State, send: Send, normalize ? `select ${value[0].toString()} to ${value[1].toString()}` : `select ${value}`, type: "button", - onClick() { + onClick(event) { + if (event.defaultPrevented) return send({ type: "PRESET.CLICK", value }) }, }) diff --git a/packages/machines/date-picker/src/date-picker.types.ts b/packages/machines/date-picker/src/date-picker.types.ts index 1a8c502a61..d816ab6d36 100644 --- a/packages/machines/date-picker/src/date-picker.types.ts +++ b/packages/machines/date-picker/src/date-picker.types.ts @@ -317,11 +317,11 @@ export interface TableCellProps { } export interface TableCellState { - isFocused: boolean - isSelectable: boolean - isSelected: boolean + focused: boolean + selectable: boolean + selected: boolean valueText: string - readonly isDisabled: boolean + readonly disabled: boolean } export interface DayTableCellProps { @@ -331,20 +331,20 @@ export interface DayTableCellProps { } export interface DayTableCellState { - isInvalid: boolean - isDisabled: boolean - isSelected: boolean - isUnavailable: boolean - isOutsideRange: boolean - isInRange: boolean - isFirstInRange: boolean - isLastInRange: boolean - isToday: boolean - isWeekend: boolean + invalid: boolean + disabled: boolean + selected: boolean + unavailable: boolean + outsideRange: boolean + inRange: boolean + firstInRange: boolean + lastInRange: boolean + today: boolean + weekend: boolean formattedDate: string - readonly isFocused: boolean + readonly focused: boolean readonly ariaLabel: string - readonly isSelectable: boolean + readonly selectable: boolean } export interface TableProps { @@ -402,11 +402,11 @@ export interface MachineApi { /** * Whether the input is focused */ - isFocused: boolean + focused: boolean /** * Whether the date picker is open */ - isOpen: boolean + open: boolean /** * The current view of the date picker */ @@ -488,13 +488,9 @@ export interface MachineApi { */ clearValue(): void /** - * Function to open the calendar. - */ - open(): void - /** - * Function to close the calendar. + * Function to open or close the calendar. */ - close(): void + setOpen(open: boolean): void /** * Function to set the selected month. */ diff --git a/packages/machines/dialog/src/dialog.connect.ts b/packages/machines/dialog/src/dialog.connect.ts index 9debea931b..1aa91cf736 100644 --- a/packages/machines/dialog/src/dialog.connect.ts +++ b/packages/machines/dialog/src/dialog.connect.ts @@ -5,16 +5,14 @@ import type { MachineApi, Send, State } from "./dialog.types" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { const ariaLabel = state.context["aria-label"] - const isOpen = state.matches("open") + const open = state.matches("open") const rendered = state.context.renderedElements return { - isOpen, - open() { - send("OPEN") - }, - close() { - send("CLOSE") + open, + setOpen(_open) { + if (_open === open) return + send(_open ? "OPEN" : "CLOSE") }, triggerProps: normalize.button({ @@ -23,10 +21,11 @@ export function connect(state: State, send: Send, normalize id: dom.getTriggerId(state.context), "aria-haspopup": "dialog", type: "button", - "aria-expanded": isOpen, - "data-state": isOpen ? "open" : "closed", + "aria-expanded": open, + "data-state": open ? "open" : "closed", "aria-controls": dom.getContentId(state.context), - onClick() { + onClick(event) { + if (event.defaultPrevented) return send("TOGGLE") }, }), @@ -34,9 +33,9 @@ export function connect(state: State, send: Send, normalize backdropProps: normalize.element({ ...parts.backdrop.attrs, dir: state.context.dir, - hidden: !isOpen, + hidden: !open, id: dom.getBackdropId(state.context), - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", }), positionerProps: normalize.element({ @@ -44,7 +43,7 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, id: dom.getPositionerId(state.context), style: { - pointerEvents: isOpen ? undefined : "none", + pointerEvents: open ? undefined : "none", }, }), @@ -52,10 +51,10 @@ export function connect(state: State, send: Send, normalize ...parts.content.attrs, dir: state.context.dir, role: state.context.role, - hidden: !isOpen, + hidden: !open, id: dom.getContentId(state.context), tabIndex: -1, - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", "aria-modal": true, "aria-label": ariaLabel || undefined, "aria-labelledby": ariaLabel || !rendered.title ? undefined : dom.getTitleId(state.context), @@ -80,6 +79,7 @@ export function connect(state: State, send: Send, normalize id: dom.getCloseTriggerId(state.context), type: "button", onClick(event) { + if (event.defaultPrevented) return event.stopPropagation() send("CLOSE") }, diff --git a/packages/machines/dialog/src/dialog.types.ts b/packages/machines/dialog/src/dialog.types.ts index afbe63ba6e..47b30de38f 100644 --- a/packages/machines/dialog/src/dialog.types.ts +++ b/packages/machines/dialog/src/dialog.types.ts @@ -121,15 +121,11 @@ export interface MachineApi { /** * Whether the dialog is open */ - isOpen: boolean - /** - * Function to open the dialog - */ - open(): void + open: boolean /** - * Function to close the dialog + * Function to open or close the dialog */ - close(): void + setOpen(open: boolean): void triggerProps: T["button"] backdropProps: T["element"] diff --git a/packages/machines/editable/src/editable.connect.ts b/packages/machines/editable/src/editable.connect.ts index 51fb7544fa..8df6febf9d 100644 --- a/packages/machines/editable/src/editable.connect.ts +++ b/packages/machines/editable/src/editable.connect.ts @@ -6,24 +6,24 @@ import { dom } from "./editable.dom" import type { MachineApi, Send, State } from "./editable.types" export function connect
state - isOpen: {String(isOpen)}
machine - isOpen: {String(api.isOpen)}
machine - isOpen: {String(api.open)}
+ - + {api.type === "loading" && } {api.title} @@ -39,7 +26,7 @@ function ToastItem({ actor }: { actor: toast.Service }) { - + ) } diff --git a/examples/next-ts/pages/tooltip.tsx b/examples/next-ts/pages/tooltip.tsx index 441ca0116b..64c7a9ba68 100644 --- a/examples/next-ts/pages/tooltip.tsx +++ b/examples/next-ts/pages/tooltip.tsx @@ -27,7 +27,7 @@ export default function Page() { Hover me - {api.isOpen && ( + {api.open && ( Tooltip @@ -38,7 +38,7 @@ export default function Page() { Over me - {api2.isOpen && ( + {api2.open && ( diff --git a/examples/nuxt-ts/package.json b/examples/nuxt-ts/package.json index 499eb489da..24c3592cd7 100644 --- a/examples/nuxt-ts/package.json +++ b/examples/nuxt-ts/package.json @@ -77,7 +77,6 @@ "@zag-js/tree-view": "workspace:*", "@zag-js/types": "workspace:*", "@zag-js/utils": "workspace:*", - "@zag-js/visually-hidden": "workspace:*", "@zag-js/vue": "workspace:*", "epic-spinners": "2.0.0", "form-serialize": "0.7.2", diff --git a/examples/nuxt-ts/pages/checkbox.vue b/examples/nuxt-ts/pages/checkbox.vue index 1f8341a947..b67cb3f00c 100644 --- a/examples/nuxt-ts/pages/checkbox.vue +++ b/examples/nuxt-ts/pages/checkbox.vue @@ -30,13 +30,13 @@ const api = computed(() => checkbox.connect(state.value, send, normalizeProps)) - Input {{ api.isChecked ? "Checked" : "Unchecked" }} + Input {{ api.checked ? "Checked" : "Unchecked" }} Indicator - api.setChecked(true)">Check - api.setChecked(false)">Uncheck + api.setChecked(true)">Check + api.setChecked(false)">Uncheck Reset Form diff --git a/examples/nuxt-ts/pages/clipboard.vue b/examples/nuxt-ts/pages/clipboard.vue index 8a68784370..d84b3a2a02 100644 --- a/examples/nuxt-ts/pages/clipboard.vue +++ b/examples/nuxt-ts/pages/clipboard.vue @@ -26,7 +26,7 @@ const api = computed(() => clipboard.connect(state.value, send, normalizeProps)) - + diff --git a/examples/nuxt-ts/pages/editable.vue b/examples/nuxt-ts/pages/editable.vue index 3fca9482d5..b6824225a5 100644 --- a/examples/nuxt-ts/pages/editable.vue +++ b/examples/nuxt-ts/pages/editable.vue @@ -20,9 +20,9 @@ const api = computed(() => editable.connect(state.value, send, normalizeProps)) - Edit + Edit - + Save Cancel diff --git a/examples/nuxt-ts/pages/hover-card.vue b/examples/nuxt-ts/pages/hover-card.vue index 03870049a8..d51305275a 100644 --- a/examples/nuxt-ts/pages/hover-card.vue +++ b/examples/nuxt-ts/pages/hover-card.vue @@ -17,7 +17,7 @@ const api = computed(() => hoverCard.connect(state.value, send, normalizeProps)) Twitter - + diff --git a/examples/nuxt-ts/pages/rating-group.vue b/examples/nuxt-ts/pages/rating-group.vue index cd46775e18..e4d3e8a90b 100644 --- a/examples/nuxt-ts/pages/rating-group.vue +++ b/examples/nuxt-ts/pages/rating-group.vue @@ -27,7 +27,7 @@ const items = computed(() => - + diff --git a/examples/nuxt-ts/pages/switch.vue b/examples/nuxt-ts/pages/switch.vue index 14c1c33423..a81ca014ac 100644 --- a/examples/nuxt-ts/pages/switch.vue +++ b/examples/nuxt-ts/pages/switch.vue @@ -23,7 +23,7 @@ const api = computed(() => zagSwitch.connect(state.value, send, normalizeProps)) - Feature is {{ api.isChecked ? "enabled" : "disabled" }} + Feature is {{ api.checked ? "enabled" : "disabled" }} diff --git a/examples/nuxt-ts/pages/tooltip.vue b/examples/nuxt-ts/pages/tooltip.vue index 1d4ac7d911..d11ce05f63 100644 --- a/examples/nuxt-ts/pages/tooltip.vue +++ b/examples/nuxt-ts/pages/tooltip.vue @@ -20,7 +20,7 @@ const api = computed(() => tooltip.connect(state.value, send, normalizeProps)) {{ state.value }} Hover me - + Tooltip with alot of text probably diff --git a/examples/preact-ts/package.json b/examples/preact-ts/package.json index 74ee7e4067..c58058d4dc 100644 --- a/examples/preact-ts/package.json +++ b/examples/preact-ts/package.json @@ -77,7 +77,6 @@ "@zag-js/tree-view": "workspace:*", "@zag-js/types": "workspace:*", "@zag-js/utils": "workspace:*", - "@zag-js/visually-hidden": "workspace:*", "match-sorter": "6.3.4", "lucide-preact": "0.372.0", "preact": "10.20.2", diff --git a/examples/solid-ts/package.json b/examples/solid-ts/package.json index e20b5f446d..b8dec359e9 100644 --- a/examples/solid-ts/package.json +++ b/examples/solid-ts/package.json @@ -87,7 +87,6 @@ "@zag-js/tree-view": "workspace:*", "@zag-js/types": "workspace:*", "@zag-js/utils": "workspace:*", - "@zag-js/visually-hidden": "workspace:*", "form-serialize": "0.7.2", "match-sorter": "6.3.4", "lucide-solid": "0.372.0", diff --git a/examples/solid-ts/src/pages/checkbox.tsx b/examples/solid-ts/src/pages/checkbox.tsx index 89e205fac4..52b1a539d9 100644 --- a/examples/solid-ts/src/pages/checkbox.tsx +++ b/examples/solid-ts/src/pages/checkbox.tsx @@ -35,17 +35,17 @@ export default function Page() { - Input {api().isChecked ? "Checked" : "Unchecked"} + Input {api().checked ? "Checked" : "Unchecked"} Indicator - api().setChecked(true)}> + api().setChecked(true)}> Check - api().setChecked(false)}> + api().setChecked(false)}> Uncheck Reset Form diff --git a/examples/solid-ts/src/pages/clipboard.tsx b/examples/solid-ts/src/pages/clipboard.tsx index 6279f4080e..7f46fc1766 100644 --- a/examples/solid-ts/src/pages/clipboard.tsx +++ b/examples/solid-ts/src/pages/clipboard.tsx @@ -30,7 +30,7 @@ export default function Page() { - }> + }> diff --git a/examples/solid-ts/src/pages/collapsible.tsx b/examples/solid-ts/src/pages/collapsible.tsx index cd26e4a204..a6b8adf341 100644 --- a/examples/solid-ts/src/pages/collapsible.tsx +++ b/examples/solid-ts/src/pages/collapsible.tsx @@ -33,8 +33,8 @@ export default function Page() { Toggle Controls - Open - Close + api().setOpen(true)}>Open + api().setOpen(false)}>Close diff --git a/examples/solid-ts/src/pages/date-picker.tsx b/examples/solid-ts/src/pages/date-picker.tsx index 6bb25adf4d..0dc42a186a 100644 --- a/examples/solid-ts/src/pages/date-picker.tsx +++ b/examples/solid-ts/src/pages/date-picker.tsx @@ -36,7 +36,7 @@ export default function Page() { - + ❌ 🗓 diff --git a/examples/solid-ts/src/pages/dialog.tsx b/examples/solid-ts/src/pages/dialog.tsx index f8ccc9ff2a..486053199e 100644 --- a/examples/solid-ts/src/pages/dialog.tsx +++ b/examples/solid-ts/src/pages/dialog.tsx @@ -25,7 +25,7 @@ export default function Page() { - + @@ -43,7 +43,7 @@ export default function Page() { Open Nested - + @@ -52,7 +52,7 @@ export default function Page() { X - parentDialog().close()} data-testid="special-close"> + parentDialog().setOpen(false)} data-testid="special-close"> Close Dialog 1 diff --git a/examples/solid-ts/src/pages/editable.tsx b/examples/solid-ts/src/pages/editable.tsx index d30b5ed4b6..7418ede7f6 100644 --- a/examples/solid-ts/src/pages/editable.tsx +++ b/examples/solid-ts/src/pages/editable.tsx @@ -28,12 +28,12 @@ export default function Page() { - + Edit - + <> Save diff --git a/examples/solid-ts/src/pages/hover-card.tsx b/examples/solid-ts/src/pages/hover-card.tsx index da62de760a..586daf5e48 100644 --- a/examples/solid-ts/src/pages/hover-card.tsx +++ b/examples/solid-ts/src/pages/hover-card.tsx @@ -23,7 +23,7 @@ export default function Page() { Twitter - + diff --git a/examples/solid-ts/src/pages/pagination.tsx b/examples/solid-ts/src/pages/pagination.tsx index 77610419fa..a2f9ef800d 100644 --- a/examples/solid-ts/src/pages/pagination.tsx +++ b/examples/solid-ts/src/pages/pagination.tsx @@ -1,6 +1,5 @@ import * as pagination from "@zag-js/pagination" import { normalizeProps, useMachine } from "@zag-js/solid" -import { visuallyHiddenStyle } from "@zag-js/visually-hidden" import { createMemo, createUniqueId, For } from "solid-js" import { paginationControls, paginationData } from "@zag-js/shared" import { StateVisualizer } from "../components/state-visualizer" @@ -56,9 +55,7 @@ export default function Page() { - - Previous Page - + Previous {(page, i) => { @@ -78,9 +75,7 @@ export default function Page() { }} - - Next Page - + Next diff --git a/examples/solid-ts/src/pages/presence.tsx b/examples/solid-ts/src/pages/presence.tsx index 7223fa53c9..77083b20f3 100644 --- a/examples/solid-ts/src/pages/presence.tsx +++ b/examples/solid-ts/src/pages/presence.tsx @@ -16,7 +16,7 @@ export default function Page() { return ( setPresent((c) => !c)}>Toggle - + { api().setNode(node) diff --git a/examples/solid-ts/src/pages/rating-group.tsx b/examples/solid-ts/src/pages/rating-group.tsx index 5f7ab5029c..e3646662a5 100644 --- a/examples/solid-ts/src/pages/rating-group.tsx +++ b/examples/solid-ts/src/pages/rating-group.tsx @@ -62,7 +62,7 @@ export default function Page() { {(index) => { const state = createMemo(() => api().getItemState({ index: index() })) return ( - {state().isHalf ? : } + {state().half ? : } ) }} diff --git a/examples/solid-ts/src/pages/switch.tsx b/examples/solid-ts/src/pages/switch.tsx index f6310021c9..7891ac5367 100644 --- a/examples/solid-ts/src/pages/switch.tsx +++ b/examples/solid-ts/src/pages/switch.tsx @@ -29,7 +29,7 @@ export default function Page() { - Feature is {api().isChecked ? "enabled" : "disabled"} + Feature is {api().checked ? "enabled" : "disabled"} diff --git a/examples/solid-ts/src/pages/toast.tsx b/examples/solid-ts/src/pages/toast.tsx index 35ab01dfe1..784cacd03f 100644 --- a/examples/solid-ts/src/pages/toast.tsx +++ b/examples/solid-ts/src/pages/toast.tsx @@ -12,23 +12,10 @@ function ToastItem(props: { actor: toast.Service }) { const [state, send] = useActor(props.actor) const api = createMemo(() => toast.connect(state, send, normalizeProps)) - const progressbarProps = createMemo(() => ({ - "data-scope": "toast", - "data-part": "progressbar", - "data-type": state.context.type, - style: { - opacity: api().isVisible ? 1 : 0, - "transform-origin": api().isRtl ? "right" : "left", - "animation-name": api().type === "loading" ? "none" : undefined, - "animation-play-state": api().isPaused ? "paused" : "running", - "animation-duration": `${state.context.duration}ms`, - }, - })) - return ( - + {api().type === "loading" && } {api().title} diff --git a/examples/solid-ts/src/pages/tooltip.tsx b/examples/solid-ts/src/pages/tooltip.tsx index cf003e2a6c..2d1c53080e 100644 --- a/examples/solid-ts/src/pages/tooltip.tsx +++ b/examples/solid-ts/src/pages/tooltip.tsx @@ -20,7 +20,7 @@ export default function Page() { Hover me - + @@ -34,7 +34,7 @@ export default function Page() { Over me - + diff --git a/examples/svelte-ts/package.json b/examples/svelte-ts/package.json index 9dc0c8c1af..9c8874415d 100644 --- a/examples/svelte-ts/package.json +++ b/examples/svelte-ts/package.json @@ -79,7 +79,6 @@ "@zag-js/tree-view": "workspace:*", "@zag-js/types": "workspace:*", "@zag-js/utils": "workspace:*", - "@zag-js/visually-hidden": "workspace:*", "form-serialize": "0.7.2", "match-sorter": "6.3.4", "lucide-svelte": "0.372.0", diff --git a/examples/svelte-ts/src/lib/components/toast-item.svelte b/examples/svelte-ts/src/lib/components/toast-item.svelte index 4defff7ff5..a3a23cd578 100644 --- a/examples/svelte-ts/src/lib/components/toast-item.svelte +++ b/examples/svelte-ts/src/lib/components/toast-item.svelte @@ -1,6 +1,7 @@ - - - {api.title} - {api.description} - Close - + + + {api.title} + {api.description} + + + + diff --git a/examples/svelte-ts/src/routes/accordion.svelte b/examples/svelte-ts/src/routes/accordion.svelte index 1ad9cf8e5f..155564898b 100644 --- a/examples/svelte-ts/src/routes/accordion.svelte +++ b/examples/svelte-ts/src/routes/accordion.svelte @@ -9,11 +9,11 @@ const controls = useControls(accordionControls) - const [_state, send] = useMachine(accordion.machine({ id: "1" }), { + const [snapshot, send] = useMachine(accordion.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(accordion.connect(_state, send, normalizeProps)) + const api = $derived(accordion.connect(snapshot, send, normalizeProps)) @@ -38,5 +38,5 @@ - + diff --git a/examples/svelte-ts/src/routes/avatar.svelte b/examples/svelte-ts/src/routes/avatar.svelte index 85f47bb29b..7f8e9d00e0 100644 --- a/examples/svelte-ts/src/routes/avatar.svelte +++ b/examples/svelte-ts/src/routes/avatar.svelte @@ -11,8 +11,8 @@ let src = $state(images[0]) let showImage = $state(true) - const [_state, send] = useMachine(avatar.machine({ id: "1" })) - const api = $derived(avatar.connect(_state, send, normalizeProps)) + const [snapshot, send] = useMachine(avatar.machine({ id: "1" })) + const api = $derived(avatar.connect(snapshot, send, normalizeProps)) @@ -31,5 +31,5 @@ - + diff --git a/examples/svelte-ts/src/routes/carousel.svelte b/examples/svelte-ts/src/routes/carousel.svelte index 56d238d2f1..cf168d6005 100644 --- a/examples/svelte-ts/src/routes/carousel.svelte +++ b/examples/svelte-ts/src/routes/carousel.svelte @@ -8,11 +8,11 @@ const controls = useControls(carouselControls) - const [_state, send] = useMachine(carousel.machine({ id: "1", index: 0, spacing: "20px", slidesPerView: 2 }), { + const [snapshot, send] = useMachine(carousel.machine({ id: "1", index: 0, spacing: "20px", slidesPerView: 2 }), { // context: controls.context, }) - const api = $derived(carousel.connect(_state, send, normalizeProps)) + const api = $derived(carousel.connect(snapshot, send, normalizeProps)) @@ -32,5 +32,5 @@ - + diff --git a/examples/svelte-ts/src/routes/checkbox.svelte b/examples/svelte-ts/src/routes/checkbox.svelte index 8066ec2d01..b6afdd4d5b 100644 --- a/examples/svelte-ts/src/routes/checkbox.svelte +++ b/examples/svelte-ts/src/routes/checkbox.svelte @@ -9,11 +9,11 @@ const controls = useControls(checkboxControls) - const [_state, send] = useMachine(checkbox.machine({ id: "1" }), { + const [snapshot, send] = useMachine(checkbox.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(checkbox.connect(_state, send, normalizeProps)) + const api = $derived(checkbox.connect(snapshot, send, normalizeProps)) @@ -25,19 +25,19 @@ > - - Input {api.isChecked ? "Checked" : "Unchecked"} + + Input {api.checked ? "Checked" : "Unchecked"} Indicator - api.setChecked(true)}>Check - api.setChecked(false)}>Uncheck + api.setChecked(true)}>Check + api.setChecked(false)}>Uncheck Reset Form - + diff --git a/examples/svelte-ts/src/routes/clipboard.svelte b/examples/svelte-ts/src/routes/clipboard.svelte index 0e8c2ca9d5..b738a8ade6 100644 --- a/examples/svelte-ts/src/routes/clipboard.svelte +++ b/examples/svelte-ts/src/routes/clipboard.svelte @@ -9,7 +9,7 @@ const controls = useControls(clipboardControls) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( clipboard.machine({ id: "1", value: "https://github/com/chakra-ui/zag", @@ -19,7 +19,7 @@ }, ) - const api = $derived(clipboard.connect(_state, send, normalizeProps)) + const api = $derived(clipboard.connect(snapshot, send, normalizeProps)) @@ -29,7 +29,7 @@ - {#if api.isCopied} + {#if api.copied} {:else} @@ -42,5 +42,5 @@ - + diff --git a/examples/svelte-ts/src/routes/collapsible.svelte b/examples/svelte-ts/src/routes/collapsible.svelte index f3dc09de4b..38213d6bba 100644 --- a/examples/svelte-ts/src/routes/collapsible.svelte +++ b/examples/svelte-ts/src/routes/collapsible.svelte @@ -8,11 +8,11 @@ const controls = useControls(collapsibleControls) - const [_state, send] = useMachine(collapsible.machine({ id: "1" }), { + const [snapshot, send] = useMachine(collapsible.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(collapsible.connect(_state, send, normalizeProps)) + const api = $derived(collapsible.connect(snapshot, send, normalizeProps)) @@ -31,11 +31,11 @@ Toggle Controls - Open - Close + api.setOpen(true)}>Open + api.setOpen(false)}>Close - + diff --git a/examples/svelte-ts/src/routes/color-picker.svelte b/examples/svelte-ts/src/routes/color-picker.svelte index 5f67febf57..8907223454 100644 --- a/examples/svelte-ts/src/routes/color-picker.svelte +++ b/examples/svelte-ts/src/routes/color-picker.svelte @@ -11,7 +11,7 @@ const controls = useControls(colorPickerControls) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( colorPicker.machine({ id: "1", name: "color", @@ -23,7 +23,7 @@ }, ) - const api = $derived(colorPicker.connect(_state, send, normalizeProps)) + const api = $derived(colorPicker.connect(snapshot, send, normalizeProps)) @@ -128,7 +128,7 @@ - + {#snippet EyeDropIcon()} diff --git a/examples/svelte-ts/src/routes/combobox.svelte b/examples/svelte-ts/src/routes/combobox.svelte index 911bc12e9b..3fb252f673 100644 --- a/examples/svelte-ts/src/routes/combobox.svelte +++ b/examples/svelte-ts/src/routes/combobox.svelte @@ -19,7 +19,7 @@ controls.setContext("collection", collection) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( combobox.machine({ id: "1", collection, @@ -39,7 +39,7 @@ }, ) - const api = $derived(combobox.connect(_state, send, normalizeProps)) + const api = $derived(combobox.connect(snapshot, send, normalizeProps)) $inspect(api.inputValue) @@ -71,5 +71,5 @@ - + diff --git a/examples/svelte-ts/src/routes/context-menu.svelte b/examples/svelte-ts/src/routes/context-menu.svelte index 8db193d270..7733fc7946 100644 --- a/examples/svelte-ts/src/routes/context-menu.svelte +++ b/examples/svelte-ts/src/routes/context-menu.svelte @@ -4,14 +4,14 @@ import * as menu from "@zag-js/menu" import { normalizeProps, portal, useMachine } from "@zag-js/svelte" - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( menu.machine({ id: "1", onSelect: console.log, }), ) - const api = $derived(menu.connect(_state, send, normalizeProps)) + const api = $derived(menu.connect(snapshot, send, normalizeProps)) @@ -27,5 +27,5 @@ - + diff --git a/examples/svelte-ts/src/routes/file-upload.svelte b/examples/svelte-ts/src/routes/file-upload.svelte index 17e4c44ae0..4d4fa1eea8 100644 --- a/examples/svelte-ts/src/routes/file-upload.svelte +++ b/examples/svelte-ts/src/routes/file-upload.svelte @@ -8,11 +8,11 @@ const controls = useControls(fileUploadControls) - const [state, send] = useMachine(fileUpload.machine({ id: "1" }), { + const [snapshot, send] = useMachine(fileUpload.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(fileUpload.connect(state, send, normalizeProps)) + const api = $derived(fileUpload.connect(snapshot, send, normalizeProps)) @@ -40,5 +40,5 @@ - + diff --git a/examples/svelte-ts/src/routes/floating-panel.svelte b/examples/svelte-ts/src/routes/floating-panel.svelte index 332450b06b..c6b14e79fa 100644 --- a/examples/svelte-ts/src/routes/floating-panel.svelte +++ b/examples/svelte-ts/src/routes/floating-panel.svelte @@ -9,11 +9,11 @@ const controls = useControls(floatingPanelControls) - const [_state, send] = useMachine(floatingPanel.machine({ id: "1" }), { + const [snapshot, send] = useMachine(floatingPanel.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(floatingPanel.connect(_state, send, normalizeProps)) + const api = $derived(floatingPanel.connect(snapshot, send, normalizeProps)) @@ -58,5 +58,5 @@ - + diff --git a/examples/svelte-ts/src/routes/hover-card.svelte b/examples/svelte-ts/src/routes/hover-card.svelte index ee8de30b40..0da60ac927 100644 --- a/examples/svelte-ts/src/routes/hover-card.svelte +++ b/examples/svelte-ts/src/routes/hover-card.svelte @@ -8,22 +8,22 @@ const controls = useControls(hoverCardControls) - const [state, send] = useMachine(hoverCard.machine({ id: "1" }), { + const [snapshot, send] = useMachine(hoverCard.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(hoverCard.connect(state, send, normalizeProps)) + const api = $derived(hoverCard.connect(snapshot, send, normalizeProps)) Twitter - {#if api.isOpen} + {#if api.open} - + Twitter Preview Twitter @@ -36,5 +36,5 @@ - + diff --git a/examples/svelte-ts/src/routes/menu-options.svelte b/examples/svelte-ts/src/routes/menu-options.svelte index ecb154336b..cabbc699b3 100644 --- a/examples/svelte-ts/src/routes/menu-options.svelte +++ b/examples/svelte-ts/src/routes/menu-options.svelte @@ -11,11 +11,11 @@ let order = $state("") let type = $state([]) - const [_state, send] = useMachine(menu.machine({ id: "1" }), { + const [snapshot, send] = useMachine(menu.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(menu.connect(_state, send, normalizeProps)) + const api = $derived(menu.connect(snapshot, send, normalizeProps)) const radios = $derived( menuOptionData.order.map((item) => ({ @@ -71,5 +71,5 @@ - + diff --git a/examples/svelte-ts/src/routes/menu.svelte b/examples/svelte-ts/src/routes/menu.svelte index 4459ccef1b..7d277a4db5 100644 --- a/examples/svelte-ts/src/routes/menu.svelte +++ b/examples/svelte-ts/src/routes/menu.svelte @@ -8,11 +8,11 @@ const controls = useControls(menuControls) - const [state, send] = useMachine(menu.machine({ id: "1", onSelect: console.log }), { + const [snapshot, send] = useMachine(menu.machine({ id: "1", onSelect: console.log }), { context: controls.context, }) - const api = $derived(menu.connect(state, send, normalizeProps)) + const api = $derived(menu.connect(snapshot, send, normalizeProps)) @@ -32,5 +32,5 @@ - + diff --git a/examples/svelte-ts/src/routes/number-input.svelte b/examples/svelte-ts/src/routes/number-input.svelte index 433145fd4d..71d8a9a347 100644 --- a/examples/svelte-ts/src/routes/number-input.svelte +++ b/examples/svelte-ts/src/routes/number-input.svelte @@ -8,16 +8,16 @@ const controls = useControls(numberInputControls) - const [_state, send] = useMachine(numberInput.machine({ id: "1" }), { + const [snapshot, send] = useMachine(numberInput.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(numberInput.connect(_state, send, normalizeProps)) + const api = $derived(numberInput.connect(snapshot, send, normalizeProps)) - + Enter number: @@ -29,5 +29,5 @@ - + diff --git a/examples/svelte-ts/src/routes/pagination.svelte b/examples/svelte-ts/src/routes/pagination.svelte index 18f3c426d9..7a8cf7b012 100644 --- a/examples/svelte-ts/src/routes/pagination.svelte +++ b/examples/svelte-ts/src/routes/pagination.svelte @@ -9,7 +9,7 @@ const controls = useControls(paginationControls) let details = $state({}) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( pagination.machine({ id: "1", count: paginationData.length, @@ -22,7 +22,7 @@ }, ) - const api = $derived(pagination.connect(_state, send, normalizeProps)) + const api = $derived(pagination.connect(snapshot, send, normalizeProps)) const data = $derived(api.slice(paginationData)) @@ -82,5 +82,5 @@ - + diff --git a/examples/svelte-ts/src/routes/pin-input.svelte b/examples/svelte-ts/src/routes/pin-input.svelte index eee5614dd5..4e6b2f7a5e 100644 --- a/examples/svelte-ts/src/routes/pin-input.svelte +++ b/examples/svelte-ts/src/routes/pin-input.svelte @@ -9,7 +9,7 @@ const controls = useControls(pinInputControls) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( pinInput.machine({ name: "test", id: "1", @@ -19,7 +19,7 @@ }, ) - const api = $derived(pinInput.connect(_state, send, normalizeProps)) + const api = $derived(pinInput.connect(snapshot, send, normalizeProps)) @@ -46,5 +46,5 @@ - + diff --git a/examples/svelte-ts/src/routes/popover.svelte b/examples/svelte-ts/src/routes/popover.svelte index f901b26b5b..1c0f5589fb 100644 --- a/examples/svelte-ts/src/routes/popover.svelte +++ b/examples/svelte-ts/src/routes/popover.svelte @@ -8,11 +8,11 @@ const controls = useControls(popoverControls) - const [state, send] = useMachine(popover.machine({ id: "1" }), { + const [snapshot, send] = useMachine(popover.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(popover.connect(state, send, normalizeProps)) + const api = $derived(popover.connect(snapshot, send, normalizeProps)) @@ -29,7 +29,7 @@ - + Popover Title @@ -48,5 +48,5 @@ - + diff --git a/examples/svelte-ts/src/routes/progress.svelte b/examples/svelte-ts/src/routes/progress.svelte index 4a4233940e..744cc5f177 100644 --- a/examples/svelte-ts/src/routes/progress.svelte +++ b/examples/svelte-ts/src/routes/progress.svelte @@ -8,11 +8,11 @@ const controls = useControls(progressControls) - const [_state, send] = useMachine(progress.machine({ id: "1" }), { + const [snapshot, send] = useMachine(progress.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(progress.connect(_state, send, normalizeProps)) + const api = $derived(progress.connect(snapshot, send, normalizeProps)) @@ -25,7 +25,7 @@ - + {api.valueAsString} @@ -39,5 +39,5 @@ - + diff --git a/examples/svelte-ts/src/routes/radio-group.svelte b/examples/svelte-ts/src/routes/radio-group.svelte index 76070535dd..111ab8046a 100644 --- a/examples/svelte-ts/src/routes/radio-group.svelte +++ b/examples/svelte-ts/src/routes/radio-group.svelte @@ -9,11 +9,11 @@ const controls = useControls(radioControls) - const [state, send] = useMachine(radio.machine({ id: "1", name: "fruit" }), { + const [snapshot, send] = useMachine(radio.machine({ id: "1", name: "fruit" }), { context: controls.context, }) - const api = $derived(radio.connect(state, send, normalizeProps)) + const api = $derived(radio.connect(snapshot, send, normalizeProps)) @@ -26,10 +26,10 @@ Fruits - + {#each radioData as opt} - + {opt.label} @@ -47,5 +47,5 @@ - + diff --git a/examples/svelte-ts/src/routes/range-slider.svelte b/examples/svelte-ts/src/routes/range-slider.svelte index 0213cab1b7..e091e846e4 100644 --- a/examples/svelte-ts/src/routes/range-slider.svelte +++ b/examples/svelte-ts/src/routes/range-slider.svelte @@ -9,7 +9,7 @@ const controls = useControls(sliderControls) - const [state, send] = useMachine( + const [snapshot, send] = useMachine( slider.machine({ id: "1", name: "quantity", @@ -18,7 +18,7 @@ { context: controls.context }, ) - const api = $derived(slider.connect(state, send, normalizeProps)) + const api = $derived(slider.connect(snapshot, send, normalizeProps)) @@ -37,7 +37,7 @@ - + {#each api.value as _, index} @@ -57,5 +57,5 @@ - + diff --git a/examples/svelte-ts/src/routes/rating-group.svelte b/examples/svelte-ts/src/routes/rating-group.svelte index 9eb49779cb..0b0b648801 100644 --- a/examples/svelte-ts/src/routes/rating-group.svelte +++ b/examples/svelte-ts/src/routes/rating-group.svelte @@ -8,11 +8,11 @@ const controls = useControls(ratingControls) - const [state, send] = useMachine(rating.machine({ id: "1", value: 2.5 }), { + const [snapshot, send] = useMachine(rating.machine({ id: "1", value: 2.5 }), { context: controls.context, }) - const api = $derived(rating.connect(state, send, normalizeProps)) + const api = $derived(rating.connect(snapshot, send, normalizeProps)) {#snippet HalfStar()} @@ -50,7 +50,7 @@ {#each api.items as index} {@const itemState = api.getItemState({ index })} - {#if itemState.isHalf} + {#if itemState.half} {@render HalfStar()} {:else} {@render Star()} @@ -65,5 +65,5 @@ - + diff --git a/examples/svelte-ts/src/routes/segment-control.svelte b/examples/svelte-ts/src/routes/segment-control.svelte index 09760f00c9..b0c0bdea9c 100644 --- a/examples/svelte-ts/src/routes/segment-control.svelte +++ b/examples/svelte-ts/src/routes/segment-control.svelte @@ -8,16 +8,16 @@ const controls = useControls(radioControls) - const [state, send] = useMachine(radio.machine({ id: "2", name: "fruit", orientation: "horizontal" }), { + const [snapshot, send] = useMachine(radio.machine({ id: "2", name: "fruit", orientation: "horizontal" }), { context: controls.context, }) - const api = $derived(radio.connect(state, send, normalizeProps)) + const api = $derived(radio.connect(snapshot, send, normalizeProps)) - + {#each radioData as opt} @@ -31,5 +31,5 @@ - + diff --git a/examples/svelte-ts/src/routes/select.svelte b/examples/svelte-ts/src/routes/select.svelte index c9ac118008..6c920ebcdd 100644 --- a/examples/svelte-ts/src/routes/select.svelte +++ b/examples/svelte-ts/src/routes/select.svelte @@ -9,7 +9,7 @@ const controls = useControls(selectControls) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( select.machine({ id: "1", name: "select", @@ -20,7 +20,7 @@ }, ) - const api = $derived(select.connect(_state, send, normalizeProps)) + const api = $derived(select.connect(snapshot, send, normalizeProps)) @@ -71,5 +71,5 @@ - + diff --git a/examples/svelte-ts/src/routes/signature-pad.svelte b/examples/svelte-ts/src/routes/signature-pad.svelte index 12cf0d019e..4682c3dc86 100644 --- a/examples/svelte-ts/src/routes/signature-pad.svelte +++ b/examples/svelte-ts/src/routes/signature-pad.svelte @@ -12,7 +12,7 @@ let url = $state("") const setUrl = (value: string) => (url = value) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( signaturePad.machine({ id: "1", onDrawEnd(details) { @@ -29,7 +29,7 @@ }, ) - const api = $derived(signaturePad.connect(_state, send, normalizeProps)) + const api = $derived(signaturePad.connect(snapshot, send, normalizeProps)) @@ -69,5 +69,5 @@ - + diff --git a/examples/svelte-ts/src/routes/slider.svelte b/examples/svelte-ts/src/routes/slider.svelte index af2fa2c5ba..2082542b29 100644 --- a/examples/svelte-ts/src/routes/slider.svelte +++ b/examples/svelte-ts/src/routes/slider.svelte @@ -9,7 +9,7 @@ const controls = useControls(sliderControls) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( slider.machine({ id: "1", name: "quantity", @@ -20,7 +20,7 @@ }, ) - const api = $derived(slider.connect(_state, send, normalizeProps)) + const api = $derived(slider.connect(snapshot, send, normalizeProps)) @@ -60,5 +60,5 @@ - + diff --git a/examples/svelte-ts/src/routes/switch.svelte b/examples/svelte-ts/src/routes/switch.svelte index 5b643b2708..dc497cfc5f 100644 --- a/examples/svelte-ts/src/routes/switch.svelte +++ b/examples/svelte-ts/src/routes/switch.svelte @@ -8,11 +8,11 @@ const controls = useControls(switchControls) - const [state, send] = useMachine(zagSwitch.machine({ id: "1", name: "switch" }), { + const [snapshot, send] = useMachine(zagSwitch.machine({ id: "1", name: "switch" }), { context: controls.context, }) - const api = $derived(zagSwitch.connect(state, send, normalizeProps)) + const api = $derived(zagSwitch.connect(snapshot, send, normalizeProps)) @@ -20,12 +20,12 @@ - + - Feature is {api.isChecked ? "enabled" : "disabled"} + Feature is {api.checked ? "enabled" : "disabled"} - + diff --git a/examples/svelte-ts/src/routes/tabs.svelte b/examples/svelte-ts/src/routes/tabs.svelte index f3419dab4c..9591f2505d 100644 --- a/examples/svelte-ts/src/routes/tabs.svelte +++ b/examples/svelte-ts/src/routes/tabs.svelte @@ -8,7 +8,7 @@ const controls = useControls(tabsControls) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( tabs.machine({ id: "1", value: "nils", @@ -18,12 +18,12 @@ }, ) - const api = $derived(tabs.connect(_state, send, normalizeProps)) + const api = $derived(tabs.connect(snapshot, send, normalizeProps)) - + {#each tabsData as data} @@ -44,5 +44,5 @@ - + diff --git a/examples/svelte-ts/src/routes/tags-input.svelte b/examples/svelte-ts/src/routes/tags-input.svelte index 1cfe03fef5..f832d7a26f 100644 --- a/examples/svelte-ts/src/routes/tags-input.svelte +++ b/examples/svelte-ts/src/routes/tags-input.svelte @@ -12,7 +12,7 @@ const controls = useControls(tagsInputControls) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( tagsInput.machine({ id: "1", value: ["React", "Vue"], @@ -22,7 +22,7 @@ }, ) - const api = $derived(tagsInput.connect(_state, send, normalizeProps)) + const api = $derived(tagsInput.connect(snapshot, send, normalizeProps)) @@ -54,5 +54,5 @@ - + diff --git a/examples/svelte-ts/src/routes/toast.svelte b/examples/svelte-ts/src/routes/toast.svelte index 44d5a1bbe1..97f11649ff 100644 --- a/examples/svelte-ts/src/routes/toast.svelte +++ b/examples/svelte-ts/src/routes/toast.svelte @@ -9,7 +9,7 @@ const controls = useControls(toastControls) - const [state, send] = useMachine( + const [snapshot, send] = useMachine( toast.group.machine({ id: "1", placement: "bottom-end", @@ -21,7 +21,7 @@ }, ) - const api = $derived(toast.group.connect(state, send, normalizeProps)) + const api = $derived(toast.group.connect(snapshot, send, normalizeProps)) let id: string | undefined = "" @@ -73,5 +73,5 @@ - + diff --git a/examples/svelte-ts/src/routes/toggle-group.svelte b/examples/svelte-ts/src/routes/toggle-group.svelte index ad8f226d4b..0d58f6fc0f 100644 --- a/examples/svelte-ts/src/routes/toggle-group.svelte +++ b/examples/svelte-ts/src/routes/toggle-group.svelte @@ -8,11 +8,11 @@ const controls = useControls(toggleGroupControls) - const [_state, send] = useMachine(toggle.machine({ id: "1" }), { + const [snapshot, send] = useMachine(toggle.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(toggle.connect(_state, send, normalizeProps)) + const api = $derived(toggle.connect(snapshot, send, normalizeProps)) @@ -27,5 +27,5 @@ - + diff --git a/examples/svelte-ts/src/routes/tooltip.svelte b/examples/svelte-ts/src/routes/tooltip.svelte index 49771ece97..1402169fdf 100644 --- a/examples/svelte-ts/src/routes/tooltip.svelte +++ b/examples/svelte-ts/src/routes/tooltip.svelte @@ -7,23 +7,23 @@ const id = "tip-1" const id2 = "tip-2" - const [_state, send] = useMachine(tooltip.machine({ id })) - const [_state2, send2] = useMachine(tooltip.machine({ id: id2 })) + const [snapshot, send] = useMachine(tooltip.machine({ id })) + const [snapshot2, send2] = useMachine(tooltip.machine({ id: id2 })) - const api = $derived(tooltip.connect(_state, send, normalizeProps)) - const api2 = $derived(tooltip.connect(_state2, send2, normalizeProps)) + const api = $derived(tooltip.connect(snapshot, send, normalizeProps)) + const api2 = $derived(tooltip.connect(snapshot2, send2, normalizeProps)) Hover me - {#if api.isOpen} + {#if api.open} Tooltip {/if} Over me - {#if api2.isOpen} + {#if api2.open} Tooltip 2 @@ -32,6 +32,6 @@ - - + + diff --git a/examples/svelte-ts/src/routes/tour.svelte b/examples/svelte-ts/src/routes/tour.svelte index 83a7e1ac6a..560698f068 100644 --- a/examples/svelte-ts/src/routes/tour.svelte +++ b/examples/svelte-ts/src/routes/tour.svelte @@ -7,11 +7,11 @@ const controls = useControls(tourControls) - const [state, send] = useMachine(tour.machine({ id: "1", steps: tourData }), { + const [snapshot, send] = useMachine(tour.machine({ id: "1", steps: tourData }), { context: controls.context, }) - const api = $derived(tour.connect(state, send, normalizeProps)) + const api = $derived(tour.connect(snapshot, send, normalizeProps)) @@ -20,9 +20,9 @@ Step 1 - + Step 2 - + Iframe Content @@ -37,13 +37,13 @@ - - + + {#if api.currentStep} - + {api.currentStep.title} {api.currentStep.description} diff --git a/examples/svelte-ts/src/routes/tree-view.svelte b/examples/svelte-ts/src/routes/tree-view.svelte index f3026b886a..5d8c97de7e 100644 --- a/examples/svelte-ts/src/routes/tree-view.svelte +++ b/examples/svelte-ts/src/routes/tree-view.svelte @@ -8,11 +8,11 @@ const controls = useControls(treeviewControls) - const [state, send] = useMachine(tree.machine({ id: "1" }), { + const [snapshot, send] = useMachine(tree.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(tree.connect(state, send, normalizeProps)) + const api = $derived(tree.connect(snapshot, send, normalizeProps)) @@ -69,5 +69,5 @@ - + diff --git a/examples/vue-ts/package.json b/examples/vue-ts/package.json index 63811422f6..baef86a282 100644 --- a/examples/vue-ts/package.json +++ b/examples/vue-ts/package.json @@ -78,7 +78,6 @@ "@zag-js/tree-view": "workspace:*", "@zag-js/types": "workspace:*", "@zag-js/utils": "workspace:*", - "@zag-js/visually-hidden": "workspace:*", "@zag-js/vue": "workspace:*", "epic-spinners": "2.0.0", "form-serialize": "0.7.2", diff --git a/examples/vue-ts/src/pages/checkbox.tsx b/examples/vue-ts/src/pages/checkbox.tsx index f5b1af4eb6..f494d7d5f5 100644 --- a/examples/vue-ts/src/pages/checkbox.tsx +++ b/examples/vue-ts/src/pages/checkbox.tsx @@ -39,15 +39,15 @@ export default defineComponent({ - Input {api.isChecked ? "Checked" : "Unchecked"} + Input {api.checked ? "Checked" : "Unchecked"} Indicator - api.setChecked(true)}> + api.setChecked(true)}> Check - api.setChecked(false)}> + api.setChecked(false)}> Uncheck Reset Form diff --git a/examples/vue-ts/src/pages/clipboard.tsx b/examples/vue-ts/src/pages/clipboard.tsx index bd69e93881..452ec460fb 100644 --- a/examples/vue-ts/src/pages/clipboard.tsx +++ b/examples/vue-ts/src/pages/clipboard.tsx @@ -34,7 +34,7 @@ export default defineComponent({ Copy this link - {api.isCopied ? : } + {api.copied ? : } Copied! Copy diff --git a/examples/vue-ts/src/pages/collapsible.tsx b/examples/vue-ts/src/pages/collapsible.tsx index 8c4b204e92..5eda24b437 100644 --- a/examples/vue-ts/src/pages/collapsible.tsx +++ b/examples/vue-ts/src/pages/collapsible.tsx @@ -38,8 +38,8 @@ export default defineComponent({ Toggle Controls - Open - Close + api.setOpen(true)}>Open + api.setOpen(false)}>Close diff --git a/examples/vue-ts/src/pages/date-picker.tsx b/examples/vue-ts/src/pages/date-picker.tsx index 0c8ea2cd36..91c056739c 100644 --- a/examples/vue-ts/src/pages/date-picker.tsx +++ b/examples/vue-ts/src/pages/date-picker.tsx @@ -45,7 +45,7 @@ export default defineComponent({ - + ❌ 🗓 diff --git a/examples/vue-ts/src/pages/dialog.tsx b/examples/vue-ts/src/pages/dialog.tsx index d6310f7fd4..ea6e184f1d 100644 --- a/examples/vue-ts/src/pages/dialog.tsx +++ b/examples/vue-ts/src/pages/dialog.tsx @@ -30,7 +30,7 @@ export default defineComponent({ Open Dialog - {parentDialog.isOpen && ( + {parentDialog.open && ( @@ -47,7 +47,7 @@ export default defineComponent({ Open Nested - {childDialog.isOpen && ( + {childDialog.open && ( @@ -55,7 +55,7 @@ export default defineComponent({ X - parentDialog.close()} data-testid="special-close"> + parentDialog.setOpen(false)} data-testid="special-close"> Close Dialog 1 diff --git a/examples/vue-ts/src/pages/editable.tsx b/examples/vue-ts/src/pages/editable.tsx index 18c1fae366..37238315e2 100644 --- a/examples/vue-ts/src/pages/editable.tsx +++ b/examples/vue-ts/src/pages/editable.tsx @@ -29,12 +29,12 @@ export default defineComponent({ - {!api.isEditing && ( + {!api.editing && ( Edit )} - {api.isEditing && ( + {api.editing && ( <> Save diff --git a/examples/vue-ts/src/pages/hover-card.tsx b/examples/vue-ts/src/pages/hover-card.tsx index e7539bef97..9b6f4463e7 100644 --- a/examples/vue-ts/src/pages/hover-card.tsx +++ b/examples/vue-ts/src/pages/hover-card.tsx @@ -28,7 +28,7 @@ export default defineComponent({ Twitter - {api.isOpen && ( + {api.open && ( diff --git a/examples/vue-ts/src/pages/pagination.tsx b/examples/vue-ts/src/pages/pagination.tsx index 7540cc9caf..6c2f2a9bf9 100644 --- a/examples/vue-ts/src/pages/pagination.tsx +++ b/examples/vue-ts/src/pages/pagination.tsx @@ -1,6 +1,5 @@ import * as pagination from "@zag-js/pagination" import { normalizeProps, useMachine } from "@zag-js/vue" -import { visuallyHiddenStyle } from "@zag-js/visually-hidden" import { computed, defineComponent, h, Fragment } from "vue" import { paginationControls, paginationData } from "@zag-js/shared" import { StateVisualizer } from "../components/state-visualizer" @@ -60,9 +59,7 @@ export default defineComponent({ - - Previous Page - + Previous {api.pages.map((page, i) => { if (page.type === "page") @@ -81,9 +78,7 @@ export default defineComponent({ ) })} - - Next Page - + Next diff --git a/examples/vue-ts/src/pages/presence.tsx b/examples/vue-ts/src/pages/presence.tsx index 9d9ebab424..0c889bf9bb 100644 --- a/examples/vue-ts/src/pages/presence.tsx +++ b/examples/vue-ts/src/pages/presence.tsx @@ -26,7 +26,7 @@ export default defineComponent({ return ( (present.value = !present.value)}>Toggle - {api.isPresent && ( + {api.present && ( Content diff --git a/examples/vue-ts/src/pages/rating-group.tsx b/examples/vue-ts/src/pages/rating-group.tsx index b65dfecca6..5c4fbaff77 100644 --- a/examples/vue-ts/src/pages/rating-group.tsx +++ b/examples/vue-ts/src/pages/rating-group.tsx @@ -71,7 +71,7 @@ export default defineComponent({ const state = api.getItemState({ index }) return ( - {state.isHalf ? : } + {state.half ? : } ) })} diff --git a/examples/vue-ts/src/pages/switch.tsx b/examples/vue-ts/src/pages/switch.tsx index d9f7265bfb..2904483c8b 100644 --- a/examples/vue-ts/src/pages/switch.tsx +++ b/examples/vue-ts/src/pages/switch.tsx @@ -34,7 +34,7 @@ export default defineComponent({ - Feature is {api.isChecked ? "enabled" : "disabled"} + Feature is {api.checked ? "enabled" : "disabled"} diff --git a/examples/vue-ts/src/pages/toast.tsx b/examples/vue-ts/src/pages/toast.tsx index ccb081aeab..0460bcc005 100644 --- a/examples/vue-ts/src/pages/toast.tsx +++ b/examples/vue-ts/src/pages/toast.tsx @@ -19,26 +19,13 @@ const ToastItem = defineComponent({ setup(props) { const [state, send] = useActor(props.actor) const apiRef = computed(() => toast.connect(state.value, send, normalizeProps)) - const progressbarProps = computed(() => ({ - "data-scope": "toast", - "data-part": "progressbar", - "data-type": state.value.context.type, - style: { - opacity: apiRef.value.isVisible ? 1 : 0, - transformOrigin: apiRef.value.isRtl ? "right" : "left", - animationName: apiRef.value.type === "loading" ? "none" : undefined, - animationPlayState: apiRef.value.isPaused ? "paused" : "running", - animationDuration: "var(--duration)", - }, - })) - return () => { const api = apiRef.value return ( - + - + {api.type === "loading" && } {api.title} @@ -47,7 +34,7 @@ const ToastItem = defineComponent({ - + ) } }, diff --git a/examples/vue-ts/src/pages/tooltip.tsx b/examples/vue-ts/src/pages/tooltip.tsx index 824574adf3..a063f1ccc8 100644 --- a/examples/vue-ts/src/pages/tooltip.tsx +++ b/examples/vue-ts/src/pages/tooltip.tsx @@ -21,7 +21,7 @@ export default defineComponent({ Hover me - {api.isOpen && ( + {api.open && ( @@ -32,7 +32,7 @@ export default defineComponent({ )} Over me - {api2.isOpen && ( + {api2.open && ( diff --git a/packages/docs/data/api.json b/packages/docs/data/api.json index 2f23dd59b0..2365af393a 100644 --- a/packages/docs/data/api.json +++ b/packages/docs/data/api.json @@ -70,14 +70,10 @@ }, "avatar": { "api": { - "isLoaded": { + "loaded": { "type": "boolean", "description": "Whether the image is loaded." }, - "showFallback": { - "type": "boolean", - "description": "Whether the fallback is shown." - }, "setSrc": { "type": "(src: string) => void", "description": "Function to set new src." @@ -121,9 +117,9 @@ "type": "number", "description": "The current scroll progress of the carousel" }, - "isAutoplay": { + "autoPlaying": { "type": "boolean", - "description": "Whether the carousel is currently auto-playing" + "description": "Whether the carousel is auto playing" }, "canScrollNext": { "type": "boolean", @@ -209,19 +205,19 @@ }, "checkbox": { "api": { - "isChecked": { + "checked": { "type": "boolean", "description": "Whether the checkbox is checked" }, - "isDisabled": { + "disabled": { "type": "boolean", "description": "Whether the checkbox is disabled" }, - "isIndeterminate": { + "indeterminate": { "type": "boolean", "description": "Whether the checkbox is indeterminate" }, - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the checkbox is focused" }, @@ -245,27 +241,31 @@ }, "disabled": { "type": "boolean", - "description": "If `true`, the checkbox will be disabled" + "description": "Whether the checkbox is disabled" }, "invalid": { "type": "boolean", - "description": "If `true`, the checkbox is marked as invalid." + "description": "Whether the checkbox is invalid" }, "required": { "type": "boolean", - "description": "If `true`, the checkbox input is marked as required," + "description": "Whether the checkbox is required" }, "checked": { "type": "CheckedState", - "description": "If `true`, the checkbox will be checked." + "description": "The checked state of the checkbox" + }, + "readOnly": { + "type": "boolean", + "description": "Whether the checkbox is read-only" }, "onCheckedChange": { "type": "(details: CheckedChangeDetails) => void", - "description": "The callback invoked when the checked state of the `Checkbox` changes." + "description": "The callback invoked when the checked state changes." }, "name": { "type": "string", - "description": "The name of the input field in a checkbox. Useful for form submission." + "description": "The name of the input field in a checkbox.\nUseful for form submission." }, "form": { "type": "string", @@ -293,7 +293,7 @@ }, "clipboard": { "api": { - "isCopied": { + "copied": { "type": "boolean", "description": "Whether the value has been copied to the clipboard" }, @@ -339,25 +339,21 @@ }, "collapsible": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the collapsible is open." }, - "isVisible": { + "visible": { "type": "boolean", "description": "Whether the collapsible is visible (open or closing)" }, - "isDisabled": { + "disabled": { "type": "boolean", "description": "Whether the collapsible is disabled" }, - "open": { - "type": "() => void", - "description": "Function to open the collapsible." - }, - "close": { - "type": "() => void", - "description": "Function to close the collapsible." + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the collapsible." } }, "context": { @@ -402,11 +398,11 @@ }, "color-picker": { "api": { - "isDragging": { + "dragging": { "type": "boolean", "description": "Whether the color picker is being dragged" }, - "isOpen": { + "open": { "type": "boolean", "description": "Whether the color picker is open" }, @@ -446,13 +442,9 @@ "type": "(value: number) => void", "description": "Function to set the color alpha" }, - "open": { - "type": "() => void", - "description": "Function to open the color picker" - }, - "close": { - "type": "() => void", - "description": "Function to close the color picker" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the color picker" } }, "context": { @@ -544,15 +536,15 @@ }, "combobox": { "api": { - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the combobox is focused" }, - "isOpen": { + "open": { "type": "boolean", "description": "Whether the combobox is open" }, - "isInputValueEmpty": { + "inputEmpty": { "type": "boolean", "description": "Whether the combobox input value is empty" }, @@ -612,13 +604,9 @@ "type": "(props: ItemProps) => ItemState", "description": "Returns the state of a combobox item" }, - "open": { - "type": "() => void", - "description": "Function to open the combobox" - }, - "close": { - "type": "() => void", - "description": "Function to close the combobox" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the combobox" }, "collection": { "type": "Collection", @@ -795,11 +783,11 @@ }, "date-picker": { "api": { - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the input is focused" }, - "isOpen": { + "open": { "type": "boolean", "description": "Whether the date picker is open" }, @@ -883,13 +871,9 @@ "type": "() => void", "description": "Clears the selected date(s)." }, - "open": { - "type": "() => void", - "description": "Function to open the calendar." - }, - "close": { - "type": "() => void", - "description": "Function to close the calendar." + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the calendar." }, "focusMonth": { "type": "(month: number) => void", @@ -1076,17 +1060,13 @@ }, "dialog": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the dialog is open" }, - "open": { - "type": "() => void", - "description": "Function to open the dialog" - }, - "close": { - "type": "() => void", - "description": "Function to close the dialog" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the dialog" } }, "context": { @@ -1180,11 +1160,11 @@ }, "editable": { "api": { - "isEditing": { + "editing": { "type": "boolean", "description": "Whether the editable is in edit mode" }, - "isValueEmpty": { + "empty": { "type": "boolean", "description": "Whether the editable value is empty" }, @@ -1325,15 +1305,15 @@ }, "file-upload": { "api": { - "isDragging": { + "dragging": { "type": "boolean", "description": "Whether the user is dragging something over the root element" }, - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the user is focused on the dropzone element" }, - "open": { + "openFilePicker": { "type": "() => void", "description": "Function to open the file dialog" }, @@ -1449,15 +1429,19 @@ }, "floating-panel": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the panel is open" }, - "isDragging": { + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the panel" + }, + "dragging": { "type": "boolean", "description": "Whether the panel is being dragged" }, - "isResizing": { + "resizing": { "type": "boolean", "description": "Whether the panel is being resized" } @@ -1556,18 +1540,14 @@ }, "hover-card": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the hover card is open" }, - "open": { - "type": "() => void", + "setOpen": { + "type": "(open: boolean) => void", "description": "Function to open the hover card" }, - "close": { - "type": "() => void", - "description": "Function to close the hover card" - }, "reposition": { "type": "(options?: Partial) => void", "description": "Function to reposition the popover" @@ -1619,17 +1599,13 @@ }, "menu": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the menu is open" }, - "open": { - "type": "() => void", - "description": "Function to open the menu" - }, - "close": { - "type": "() => void", - "description": "Function to close the menu" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the menu" }, "highlightedValue": { "type": "string", @@ -1746,15 +1722,15 @@ }, "number-input": { "api": { - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the input is focused." }, - "isInvalid": { + "invalid": { "type": "boolean", "description": "Whether the input is invalid." }, - "isValueEmpty": { + "empty": { "type": "boolean", "description": "Whether the input value is empty." }, @@ -1939,14 +1915,6 @@ "type": "(data: V[]) => V[]", "description": "Function to slice an array of data based on the current page." }, - "isFirstPage": { - "type": "boolean", - "description": "Whether the current page is the first page." - }, - "isLastPage": { - "type": "boolean", - "description": "Whether the current page is the last page." - }, "setCount": { "type": "(count: number) => void", "description": "Function to set the total number of pages." @@ -2019,7 +1987,7 @@ "type": "string", "description": "The value of the input as a string." }, - "isValueComplete": { + "complete": { "type": "boolean", "description": "Whether all inputs are filled." }, @@ -2134,17 +2102,13 @@ "type": "boolean", "description": "Whether the popover is portalled" }, - "isOpen": { + "open": { "type": "boolean", "description": "Whether the popover is open" }, - "open": { - "type": "() => void", - "description": "Function to open the popover" - }, - "close": { - "type": "() => void", - "description": "Function to close the popover" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the popover" }, "reposition": { "type": "(options?: Partial) => void", @@ -2231,7 +2195,7 @@ }, "presence": { "api": { - "isPresent": { + "present": { "type": "boolean", "description": "Whether the node is present in the DOM." }, @@ -2351,6 +2315,10 @@ "type": "boolean", "description": "If `true`, the radio group will be disabled" }, + "readOnly": { + "type": "boolean", + "description": "Whether the checkbox is read-only" + }, "onValueChange": { "type": "(details: ValueChangeDetails) => void", "description": "Function called once a radio is checked" @@ -2384,7 +2352,7 @@ "type": "() => void", "description": "Clears the value of the rating group" }, - "isHovering": { + "hovering": { "type": "boolean", "description": "Whether the rating group is being hovered" }, @@ -2475,15 +2443,15 @@ }, "select": { "api": { - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the select is focused" }, - "isOpen": { + "open": { "type": "boolean", "description": "Whether the select is open" }, - "isValueEmpty": { + "empty": { "type": "boolean", "description": "Whether the select value is empty" }, @@ -2535,13 +2503,9 @@ "type": "(props: ItemProps) => ItemState", "description": "Returns the state of a select item" }, - "open": { - "type": "() => void", - "description": "Function to open the select" - }, - "close": { - "type": "() => void", - "description": "Function to close the select" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the select" }, "collection": { "type": "Collection", @@ -2662,11 +2626,11 @@ }, "signature-pad": { "api": { - "isEmpty": { + "empty": { "type": "boolean", "description": "Whether the signature pad is empty." }, - "isDrawing": { + "drawing": { "type": "boolean", "description": "Whether the user is currently drawing." }, @@ -2733,11 +2697,11 @@ "type": "number[]", "description": "The value of the slider." }, - "isDragging": { + "dragging": { "type": "boolean", "description": "Whether the slider is being dragged." }, - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the slider is focused." }, @@ -2840,7 +2804,7 @@ "description": "Function invoked when the slider's focused index changes" }, "getAriaValueText": { - "type": "(value: number, index: number) => string", + "type": "(details: ValueTextDetails) => string", "description": "Function that returns a human readable value for the slider thumb" }, "min": { @@ -2892,11 +2856,11 @@ }, "splitter": { "api": { - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the splitter is focused." }, - "isDragging": { + "dragging": { "type": "boolean", "description": "Whether the splitter is being dragged." }, @@ -2959,15 +2923,15 @@ }, "switch": { "api": { - "isChecked": { + "checked": { "type": "boolean", "description": "Whether the checkbox is checked" }, - "isDisabled": { + "disabled": { "type": "boolean", "description": "Whether the checkbox is disabled" }, - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the checkbox is focused" }, @@ -3001,6 +2965,10 @@ "type": "boolean", "description": "If `true`, the switch input is marked as required," }, + "readOnly": { + "type": "boolean", + "description": "Whether the switch is read-only" + }, "onCheckedChange": { "type": "(details: CheckedChangeDetails) => void", "description": "Function to call when the switch is clicked." @@ -3117,7 +3085,7 @@ }, "tags-input": { "api": { - "isEmpty": { + "empty": { "type": "boolean", "description": "Whether the tags are empty" }, @@ -3137,7 +3105,7 @@ "type": "number", "description": "The number of the tags." }, - "isAtMax": { + "atMax": { "type": "boolean", "description": "Whether the tags have reached the max limit." }, @@ -3357,18 +3325,14 @@ }, "tooltip": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the tooltip is open." }, - "open": { - "type": "() => void", + "setOpen": { + "type": "(open: boolean) => void", "description": "Function to open the tooltip." }, - "close": { - "type": "() => void", - "description": "Function to close the tooltip." - }, "reposition": { "type": "(options?: Partial) => void", "description": "Function to reposition the popover" diff --git a/packages/machines/accordion/src/accordion.connect.ts b/packages/machines/accordion/src/accordion.connect.ts index 0314780020..5e9b6219a3 100644 --- a/packages/machines/accordion/src/accordion.connect.ts +++ b/packages/machines/accordion/src/accordion.connect.ts @@ -20,9 +20,9 @@ export function connect(state: State, send: Send, normalize function getItemState(props: ItemProps): ItemState { return { - isOpen: value.includes(props.value), - isFocused: focusedValue === props.value, - isDisabled: Boolean(props.disabled ?? state.context.disabled), + expanded: value.includes(props.value), + focused: focusedValue === props.value, + disabled: Boolean(props.disabled ?? state.context.disabled), } } @@ -45,9 +45,9 @@ export function connect(state: State, send: Send, normalize ...parts.item.attrs, dir: state.context.dir, id: dom.getItemId(state.context, props.value), - "data-state": itemState.isOpen ? "open" : "closed", - "data-focus": dataAttr(itemState.isFocused), - "data-disabled": dataAttr(itemState.isDisabled), + "data-state": itemState.expanded ? "open" : "closed", + "data-focus": dataAttr(itemState.focused), + "data-disabled": dataAttr(itemState.disabled), "data-orientation": state.context.orientation, }) }, @@ -60,10 +60,10 @@ export function connect(state: State, send: Send, normalize role: "region", id: dom.getItemContentId(state.context, props.value), "aria-labelledby": dom.getItemTriggerId(state.context, props.value), - hidden: !itemState.isOpen, - "data-state": itemState.isOpen ? "open" : "closed", - "data-disabled": dataAttr(itemState.isDisabled), - "data-focus": dataAttr(itemState.isFocused), + hidden: !itemState.expanded, + "data-state": itemState.expanded ? "open" : "closed", + "data-disabled": dataAttr(itemState.disabled), + "data-focus": dataAttr(itemState.focused), "data-orientation": state.context.orientation, }) }, @@ -74,9 +74,9 @@ export function connect(state: State, send: Send, normalize ...parts.itemIndicator.attrs, dir: state.context.dir, "aria-hidden": true, - "data-state": itemState.isOpen ? "open" : "closed", - "data-disabled": dataAttr(itemState.isDisabled), - "data-focus": dataAttr(itemState.isFocused), + "data-state": itemState.expanded ? "open" : "closed", + "data-disabled": dataAttr(itemState.disabled), + "data-focus": dataAttr(itemState.focused), "data-orientation": state.context.orientation, }) }, @@ -91,22 +91,22 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, id: dom.getItemTriggerId(state.context, value), "aria-controls": dom.getItemContentId(state.context, value), - "aria-expanded": itemState.isOpen, - disabled: itemState.isDisabled, + "aria-expanded": itemState.expanded, + disabled: itemState.disabled, "data-orientation": state.context.orientation, - "aria-disabled": itemState.isDisabled, - "data-state": itemState.isOpen ? "open" : "closed", + "aria-disabled": itemState.disabled, + "data-state": itemState.expanded ? "open" : "closed", "data-ownedby": dom.getRootId(state.context), onFocus() { - if (itemState.isDisabled) return + if (itemState.disabled) return send({ type: "TRIGGER.FOCUS", value }) }, onBlur() { - if (itemState.isDisabled) return + if (itemState.disabled) return send("TRIGGER.BLUR") }, onClick(event) { - if (itemState.isDisabled) return + if (itemState.disabled) return if (isSafari()) { event.currentTarget.focus() } @@ -114,7 +114,7 @@ export function connect(state: State, send: Send, normalize }, onKeyDown(event) { if (event.defaultPrevented) return - if (itemState.isDisabled) return + if (itemState.disabled) return const keyMap: EventKeyMap = { ArrowDown() { diff --git a/packages/machines/accordion/src/accordion.types.ts b/packages/machines/accordion/src/accordion.types.ts index 93276bd2d1..7f98b6cfe5 100644 --- a/packages/machines/accordion/src/accordion.types.ts +++ b/packages/machines/accordion/src/accordion.types.ts @@ -50,11 +50,11 @@ interface PublicContext extends DirectionProperty, CommonProperties { /** * The callback fired when the state of opened/closed accordion items changes. */ - onValueChange?: (details: ValueChangeDetails) => void + onValueChange?(details: ValueChangeDetails): void /** * The callback fired when the focused accordion item changes. */ - onFocusChange?: (details: FocusChangeDetails) => void + onFocusChange?(details: FocusChangeDetails): void /** * The orientation of the accordion items. */ @@ -94,14 +94,29 @@ export type Send = S.Send * -----------------------------------------------------------------------------*/ export interface ItemProps { + /** + * The value of the accordion item. + */ value: string + /** + * Whether the accordion item is disabled. + */ disabled?: boolean } export interface ItemState { - isOpen: boolean - isFocused: boolean - isDisabled: boolean + /** + * Whether the accordion item is expanded. + */ + expanded: boolean + /** + * Whether the accordion item is focused. + */ + focused: boolean + /** + * Whether the accordion item is disabled. + */ + disabled: boolean } export interface MachineApi { @@ -120,7 +135,8 @@ export interface MachineApi { /** * Gets the state of an accordion item. */ - getItemState: (props: ItemProps) => ItemState + getItemState(props: ItemProps): ItemState + rootProps: T["element"] getItemProps(props: ItemProps): T["element"] getItemContentProps(props: ItemProps): T["element"] diff --git a/packages/machines/avatar/src/avatar.connect.ts b/packages/machines/avatar/src/avatar.connect.ts index 2b146a8686..9d8ec7535a 100644 --- a/packages/machines/avatar/src/avatar.connect.ts +++ b/packages/machines/avatar/src/avatar.connect.ts @@ -4,12 +4,9 @@ import { dom } from "./avatar.dom" import type { MachineApi, Send, State } from "./avatar.types" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { - const isLoaded = state.matches("loaded") - const showFallback = !isLoaded - + const loaded = state.matches("loaded") return { - isLoaded, - showFallback, + loaded, setSrc(src) { send({ type: "SRC.SET", src }) }, @@ -28,10 +25,10 @@ export function connect(state: State, send: Send, normalize imageProps: normalize.img({ ...parts.image.attrs, - hidden: !isLoaded, + hidden: !loaded, dir: state.context.dir, id: dom.getImageId(state.context), - "data-state": isLoaded ? "visible" : "hidden", + "data-state": loaded ? "visible" : "hidden", onLoad() { send({ type: "IMG.LOADED", src: "element" }) }, @@ -44,8 +41,8 @@ export function connect(state: State, send: Send, normalize ...parts.fallback.attrs, dir: state.context.dir, id: dom.getFallbackId(state.context), - hidden: isLoaded, - "data-state": isLoaded ? "hidden" : "visible", + hidden: loaded, + "data-state": loaded ? "hidden" : "visible", }), } } diff --git a/packages/machines/avatar/src/avatar.types.ts b/packages/machines/avatar/src/avatar.types.ts index 28ff0eef10..6421d361e1 100644 --- a/packages/machines/avatar/src/avatar.types.ts +++ b/packages/machines/avatar/src/avatar.types.ts @@ -5,8 +5,10 @@ import type { CommonProperties, DirectionProperty, PropTypes, RequiredBy } from * Callback details * -----------------------------------------------------------------------------*/ +export type LoadStatus = "error" | "loaded" + export interface StatusChangeDetails { - status: "loaded" | "error" + status: LoadStatus } /* ----------------------------------------------------------------------------- @@ -44,11 +46,7 @@ export interface MachineApi { /** * Whether the image is loaded. */ - isLoaded: boolean - /** - * Whether the fallback is shown. - */ - showFallback: boolean + loaded: boolean /** * Function to set new src. */ diff --git a/packages/machines/avatar/src/index.ts b/packages/machines/avatar/src/index.ts index 53c0204402..4ecd5fdbc8 100644 --- a/packages/machines/avatar/src/index.ts +++ b/packages/machines/avatar/src/index.ts @@ -2,4 +2,4 @@ export { anatomy } from "./avatar.anatomy" export { connect } from "./avatar.connect" export { machine } from "./avatar.machine" export * from "./avatar.props" -export type { MachineApi as Api, UserDefinedContext as Context, StatusChangeDetails } from "./avatar.types" +export type { MachineApi as Api, UserDefinedContext as Context, StatusChangeDetails, LoadStatus } from "./avatar.types" diff --git a/packages/machines/carousel/src/carousel.connect.ts b/packages/machines/carousel/src/carousel.connect.ts index b199e93c06..810902145b 100644 --- a/packages/machines/carousel/src/carousel.connect.ts +++ b/packages/machines/carousel/src/carousel.connect.ts @@ -2,14 +2,14 @@ import { dataAttr, isDom } from "@zag-js/dom-query" import type { NormalizeProps, PropTypes } from "@zag-js/types" import { parts } from "./carousel.anatomy" import { dom } from "./carousel.dom" -import type { MachineApi, Send, IndicatorProps, ItemProps, State, ItemState } from "./carousel.types" +import type { IndicatorProps, ItemProps, ItemState, MachineApi, Send, State } from "./carousel.types" import { getSlidesInView } from "./utils/get-slide-in-view" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { const canScrollNext = state.context.canScrollNext const canScrollPrev = state.context.canScrollPrev - const isHorizontal = state.context.isHorizontal - const isAutoplay = state.matches("autoplay") + const horizontal = state.context.isHorizontal + const autoPlaying = state.matches("autoplay") const activeSnap = state.context.scrollSnaps[state.context.index] const slidesInView = isDom() ? getSlidesInView(state.context)(activeSnap) : [] @@ -18,38 +18,32 @@ export function connect(state: State, send: Send, normalize const { index } = props return { valueText: `Slide ${index + 1}`, - isCurrent: index === state.context.index, - isNext: index === state.context.index + 1, - isPrevious: index === state.context.index - 1, - isInView: slidesInView.includes(index), + current: index === state.context.index, + next: index === state.context.index + 1, + previous: index === state.context.index - 1, + inView: slidesInView.includes(index), } } return { index: state.context.index, scrollProgress: state.context.scrollProgress, - isAutoplay, + autoPlaying, canScrollNext, canScrollPrev, - scrollTo(index, jump) { send({ type: "GOTO", index, jump }) }, - scrollToNext() { send("NEXT") }, - scrollToPrevious() { send("PREV") }, - getItemState: getItemState, - play() { send("PLAY") }, - pause() { send("PAUSE") }, @@ -82,8 +76,8 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, style: { display: "flex", - flexDirection: isHorizontal ? "row" : "column", - [isHorizontal ? "height" : "width"]: "auto", + flexDirection: horizontal ? "row" : "column", + [horizontal ? "height" : "width"]: "auto", gap: "var(--slide-spacing)", transform: state.context.translateValue, transitionProperty: "transform", @@ -101,8 +95,8 @@ export function connect(state: State, send: Send, normalize ...parts.item.attrs, id: dom.getItemId(state.context, index), dir: state.context.dir, - "data-current": dataAttr(sliderState.isCurrent), - "data-inview": dataAttr(sliderState.isInView), + "data-current": dataAttr(sliderState.current), + "data-inview": dataAttr(sliderState.inView), role: "group", "aria-roledescription": "slide", "data-orientation": state.context.orientation, @@ -110,7 +104,7 @@ export function connect(state: State, send: Send, normalize style: { position: "relative", flex: "0 0 var(--slide-size)", - [isHorizontal ? "minWidth" : "minHeight"]: "0px", + [horizontal ? "minWidth" : "minHeight"]: "0px", }, }) }, diff --git a/packages/machines/carousel/src/carousel.types.ts b/packages/machines/carousel/src/carousel.types.ts index b383c1bf8e..b92e9df1bd 100644 --- a/packages/machines/carousel/src/carousel.types.ts +++ b/packages/machines/carousel/src/carousel.types.ts @@ -98,15 +98,33 @@ export type Send = S.Send * -----------------------------------------------------------------------------*/ export interface ItemProps { + /** + * The index of the item. + */ index: number } export interface ItemState { + /** + * The text value of the item. Used for accessibility. + */ valueText: string - isCurrent: boolean - isNext: boolean - isPrevious: boolean - isInView: boolean + /** + * Whether the item is the current item in the carousel + */ + current: boolean + /** + * Whether the item is the next item in the carousel + */ + next: boolean + /** + * Whether the item is the previous item in the carousel + */ + previous: boolean + /** + * Whether the item is in view + */ + inView: boolean } export interface IndicatorProps { @@ -124,9 +142,9 @@ export interface MachineApi { */ scrollProgress: number /** - * Whether the carousel is currently auto-playing + * Whether the carousel is auto playing */ - isAutoplay: boolean + autoPlaying: boolean /** * Whether the carousel is can scroll to the next slide */ diff --git a/packages/machines/checkbox/package.json b/packages/machines/checkbox/package.json index e1a9a13721..e7f490b20e 100644 --- a/packages/machines/checkbox/package.json +++ b/packages/machines/checkbox/package.json @@ -41,7 +41,6 @@ "@zag-js/types": "workspace:*", "@zag-js/dom-query": "workspace:*", "@zag-js/dom-event": "workspace:*", - "@zag-js/visually-hidden": "workspace:*", "@zag-js/form-utils": "workspace:*", "@zag-js/utils": "workspace:*" }, diff --git a/packages/machines/checkbox/src/checkbox.connect.ts b/packages/machines/checkbox/src/checkbox.connect.ts index 307448656d..ff16d983b3 100644 --- a/packages/machines/checkbox/src/checkbox.connect.ts +++ b/packages/machines/checkbox/src/checkbox.connect.ts @@ -1,38 +1,39 @@ -import { dataAttr } from "@zag-js/dom-query" +import { dataAttr, visuallyHiddenStyle } from "@zag-js/dom-query" import type { NormalizeProps, PropTypes } from "@zag-js/types" -import { visuallyHiddenStyle } from "@zag-js/visually-hidden" import { parts } from "./checkbox.anatomy" import { dom } from "./checkbox.dom" -import type { CheckedState, MachineApi, Send, State } from "./checkbox.types" +import type { MachineApi, Send, State } from "./checkbox.types" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { - const isDisabled = state.context.isDisabled - const isFocused = !isDisabled && state.context.focused - const isChecked = state.context.isChecked - const isIndeterminate = state.context.isIndeterminate + const disabled = state.context.isDisabled + const focused = !disabled && state.context.focused + const checked = state.context.isChecked + const indeterminate = state.context.isIndeterminate + const readOnly = state.context.readOnly const dataAttrs = { "data-active": dataAttr(state.context.active), - "data-focus": dataAttr(isFocused), + "data-focus": dataAttr(focused), + "data-readonly": dataAttr(readOnly), "data-hover": dataAttr(state.context.hovered), - "data-disabled": dataAttr(isDisabled), - "data-state": isIndeterminate ? "indeterminate" : state.context.checked ? "checked" : "unchecked", + "data-disabled": dataAttr(disabled), + "data-state": indeterminate ? "indeterminate" : state.context.checked ? "checked" : "unchecked", "data-invalid": dataAttr(state.context.invalid), } return { - isChecked, - isDisabled, - isIndeterminate, - isFocused, + checked, + disabled, + indeterminate, + focused, checkedState: state.context.checked, - setChecked(checked: CheckedState) { + setChecked(checked) { send({ type: "CHECKED.SET", checked, isTrusted: false }) }, toggleChecked() { - send({ type: "CHECKED.TOGGLE", checked: isChecked, isTrusted: false }) + send({ type: "CHECKED.TOGGLE", checked: checked, isTrusted: false }) }, rootProps: normalize.label({ @@ -42,11 +43,11 @@ export function connect(state: State, send: Send, normalize id: dom.getRootId(state.context), htmlFor: dom.getHiddenInputId(state.context), onPointerMove() { - if (isDisabled) return + if (disabled) return send({ type: "CONTEXT.SET", context: { hovered: true } }) }, onPointerLeave() { - if (isDisabled) return + if (disabled) return send({ type: "CONTEXT.SET", context: { hovered: false } }) }, onClick(event) { @@ -75,16 +76,16 @@ export function connect(state: State, send: Send, normalize ...parts.indicator.attrs, ...dataAttrs, dir: state.context.dir, - hidden: !isIndeterminate && !state.context.checked, + hidden: !indeterminate && !state.context.checked, }), hiddenInputProps: normalize.input({ id: dom.getHiddenInputId(state.context), type: "checkbox", required: state.context.required, - defaultChecked: isChecked, - disabled: isDisabled, - "data-disabled": dataAttr(isDisabled), + defaultChecked: checked, + disabled: disabled, + "data-disabled": dataAttr(disabled), "aria-labelledby": dom.getLabelId(state.context), "aria-invalid": state.context.invalid, name: state.context.name, @@ -92,6 +93,11 @@ export function connect(state: State, send: Send, normalize value: state.context.value, style: visuallyHiddenStyle, onChange(event) { + if (readOnly) { + event.preventDefault() + return + } + const checked = event.currentTarget.checked send({ type: "CHECKED.SET", checked, isTrusted: true }) }, diff --git a/packages/machines/checkbox/src/checkbox.props.ts b/packages/machines/checkbox/src/checkbox.props.ts index f0072b357b..46e1903a4f 100644 --- a/packages/machines/checkbox/src/checkbox.props.ts +++ b/packages/machines/checkbox/src/checkbox.props.ts @@ -13,6 +13,7 @@ export const props = createProps()([ "invalid", "name", "onCheckedChange", + "readOnly", "required", "value", ]) diff --git a/packages/machines/checkbox/src/checkbox.types.ts b/packages/machines/checkbox/src/checkbox.types.ts index b41e80e46f..d3be097554 100644 --- a/packages/machines/checkbox/src/checkbox.types.ts +++ b/packages/machines/checkbox/src/checkbox.types.ts @@ -28,27 +28,32 @@ interface PublicContext extends DirectionProperty, CommonProperties { */ ids?: ElementIds /** - * If `true`, the checkbox will be disabled + * Whether the checkbox is disabled */ disabled?: boolean /** - * If `true`, the checkbox is marked as invalid. + * Whether the checkbox is invalid */ invalid?: boolean /** - * If `true`, the checkbox input is marked as required, + * Whether the checkbox is required */ required?: boolean /** - * If `true`, the checkbox will be checked. + * The checked state of the checkbox */ checked: CheckedState /** - * The callback invoked when the checked state of the `Checkbox` changes. + * Whether the checkbox is read-only + */ + readOnly?: boolean + /** + * The callback invoked when the checked state changes. */ onCheckedChange?(details: CheckedChangeDetails): void /** - * The name of the input field in a checkbox. Useful for form submission. + * The name of the input field in a checkbox. + * Useful for form submission. */ name?: string /** @@ -120,19 +125,19 @@ export interface MachineApi { /** * Whether the checkbox is checked */ - isChecked: boolean + checked: boolean /** * Whether the checkbox is disabled */ - isDisabled: boolean | undefined + disabled: boolean | undefined /** * Whether the checkbox is indeterminate */ - isIndeterminate: boolean + indeterminate: boolean /** * Whether the checkbox is focused */ - isFocused: boolean | undefined + focused: boolean | undefined /** * The checked state of the checkbox */ diff --git a/packages/machines/clipboard/src/clipboard.connect.ts b/packages/machines/clipboard/src/clipboard.connect.ts index ed630cec6e..db267e5c61 100644 --- a/packages/machines/clipboard/src/clipboard.connect.ts +++ b/packages/machines/clipboard/src/clipboard.connect.ts @@ -5,10 +5,10 @@ import type { MachineApi, Send, State } from "./clipboard.types" import { dom } from "./clipboard.dom" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { - const isCopied = state.matches("copied") + const copied = state.matches("copied") return { - isCopied, + copied, value: state.context.value, setValue(value) { send({ type: "VALUE.SET", value }) @@ -18,23 +18,23 @@ export function connect(state: State, send: Send, normalize }, rootProps: normalize.element({ ...parts.root.attrs, - "data-copied": dataAttr(isCopied), + "data-copied": dataAttr(copied), id: dom.getRootId(state.context), }), labelProps: normalize.label({ ...parts.label.attrs, htmlFor: dom.getInputId(state.context), - "data-copied": dataAttr(isCopied), + "data-copied": dataAttr(copied), id: dom.getLabelId(state.context), }), controlProps: normalize.element({ ...parts.control.attrs, - "data-copied": dataAttr(isCopied), + "data-copied": dataAttr(copied), }), inputProps: normalize.input({ ...parts.input.attrs, defaultValue: state.context.value, - "data-copied": dataAttr(isCopied), + "data-copied": dataAttr(copied), readOnly: true, "data-readonly": "true", id: dom.getInputId(state.context), @@ -47,8 +47,8 @@ export function connect(state: State, send: Send, normalize }), triggerProps: normalize.button({ ...parts.trigger.attrs, - "aria-label": isCopied ? "Copied to clipboard" : "Copy to clipboard", - "data-copied": dataAttr(isCopied), + "aria-label": copied ? "Copied to clipboard" : "Copy to clipboard", + "data-copied": dataAttr(copied), onClick() { send({ type: "COPY" }) }, @@ -56,7 +56,7 @@ export function connect(state: State, send: Send, normalize getIndicatorProps(props) { return normalize.element({ ...parts.indicator.attrs, - hidden: props.copied !== isCopied, + hidden: props.copied !== copied, }) }, } diff --git a/packages/machines/clipboard/src/clipboard.types.ts b/packages/machines/clipboard/src/clipboard.types.ts index 89fb00c7c0..ad5c700061 100644 --- a/packages/machines/clipboard/src/clipboard.types.ts +++ b/packages/machines/clipboard/src/clipboard.types.ts @@ -58,7 +58,7 @@ export interface MachineApi { /** * Whether the value has been copied to the clipboard */ - isCopied: boolean + copied: boolean /** * The value to be copied to the clipboard */ diff --git a/packages/machines/collapsible/src/collapsible.connect.ts b/packages/machines/collapsible/src/collapsible.connect.ts index 7d2fcfd25d..7034c3daf5 100644 --- a/packages/machines/collapsible/src/collapsible.connect.ts +++ b/packages/machines/collapsible/src/collapsible.connect.ts @@ -5,39 +5,37 @@ import { dom } from "./collapsible.dom" import type { MachineApi, Send, State } from "./collapsible.types" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { - const isVisible = state.matches("open", "closing") - const isOpen = state.matches("open") + const visible = state.matches("open", "closing") + const open = state.matches("open") const height = state.context.height const width = state.context.width - const isDisabled = !!state.context.disabled + const disabled = !!state.context.disabled - const skipMountAnimation = state.context.isMountAnimationPrevented && isOpen + const skipMountAnimation = state.context.isMountAnimationPrevented && open return { - isDisabled, - isVisible, - isOpen, - open() { - send("OPEN") - }, - close() { - send("CLOSE") + disabled, + visible, + open, + setOpen(_open) { + if (_open === open) return + send(_open ? "OPEN" : "CLOSE") }, rootProps: normalize.element({ ...parts.root.attrs, - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", dir: state.context.dir, id: dom.getRootId(state.context), }), contentProps: normalize.element({ ...parts.content.attrs, - "data-state": skipMountAnimation ? undefined : isOpen ? "open" : "closed", + "data-state": skipMountAnimation ? undefined : open ? "open" : "closed", id: dom.getContentId(state.context), - "data-disabled": dataAttr(isDisabled), - hidden: !isVisible, + "data-disabled": dataAttr(disabled), + hidden: !visible, style: { "--height": height != null ? `${height}px` : undefined, "--width": width != null ? `${width}px` : undefined, @@ -49,13 +47,13 @@ export function connect(state: State, send: Send, normalize id: dom.getTriggerId(state.context), dir: state.context.dir, type: "button", - "data-state": isOpen ? "open" : "closed", - "data-disabled": dataAttr(isDisabled), + "data-state": open ? "open" : "closed", + "data-disabled": dataAttr(disabled), "aria-controls": dom.getContentId(state.context), - "aria-expanded": isVisible || false, + "aria-expanded": visible || false, onClick() { - if (isDisabled) return - send({ type: isOpen ? "CLOSE" : "OPEN", src: "trigger.click" }) + if (disabled) return + send({ type: open ? "CLOSE" : "OPEN", src: "trigger.click" }) }, }), } diff --git a/packages/machines/collapsible/src/collapsible.types.ts b/packages/machines/collapsible/src/collapsible.types.ts index 1534bcd502..a203963455 100644 --- a/packages/machines/collapsible/src/collapsible.types.ts +++ b/packages/machines/collapsible/src/collapsible.types.ts @@ -91,23 +91,20 @@ export interface MachineApi { /** * Whether the collapsible is open. */ - isOpen: boolean + open: boolean /** * Whether the collapsible is visible (open or closing) */ - isVisible: boolean + visible: boolean /** * Whether the collapsible is disabled */ - isDisabled: boolean - /** - * Function to open the collapsible. - */ - open(): void + disabled: boolean /** - * Function to close the collapsible. + * Function to open or close the collapsible. */ - close(): void + setOpen(open: boolean): void + rootProps: T["element"] triggerProps: T["button"] contentProps: T["element"] diff --git a/packages/machines/color-picker/package.json b/packages/machines/color-picker/package.json index d7a2811237..8905765bcc 100644 --- a/packages/machines/color-picker/package.json +++ b/packages/machines/color-picker/package.json @@ -44,7 +44,6 @@ "@zag-js/utils": "workspace:*", "@zag-js/form-utils": "workspace:*", "@zag-js/color-utils": "workspace:*", - "@zag-js/visually-hidden": "workspace:*", "@zag-js/popper": "workspace:*", "@zag-js/text-selection": "workspace:*", "@zag-js/types": "workspace:*" diff --git a/packages/machines/color-picker/src/color-picker.connect.ts b/packages/machines/color-picker/src/color-picker.connect.ts index f284442c8b..ad4988e790 100644 --- a/packages/machines/color-picker/src/color-picker.connect.ts +++ b/packages/machines/color-picker/src/color-picker.connect.ts @@ -8,10 +8,9 @@ import { isModifierKey, type EventKeyMap, } from "@zag-js/dom-event" -import { dataAttr, query } from "@zag-js/dom-query" +import { dataAttr, query, visuallyHiddenStyle } from "@zag-js/dom-query" import { getPlacementStyles } from "@zag-js/popper" import type { NormalizeProps, PropTypes } from "@zag-js/types" -import { visuallyHiddenStyle } from "@zag-js/visually-hidden" import { parts } from "./color-picker.anatomy" import { dom } from "./color-picker.dom" import type { @@ -32,12 +31,12 @@ export function connect(state: State, send: Send, normalize const areaValue = state.context.areaValue const valueAsString = state.context.valueAsString - const isDisabled = state.context.isDisabled - const isInteractive = state.context.isInteractive + const disabled = state.context.isDisabled + const interactive = state.context.isInteractive - const isDragging = state.hasTag("dragging") - const isOpen = state.hasTag("open") - const isFocused = state.hasTag("focused") + const dragging = state.hasTag("dragging") + const open = state.hasTag("open") + const focused = state.hasTag("focused") const getAreaChannels = (props: AreaProps) => { const channels = areaValue.getChannels() @@ -58,21 +57,19 @@ export function connect(state: State, send: Send, normalize return { value: color, valueAsString: color.toString("hex"), - isChecked: color.isEqual(value), - isDisabled: props.disabled || !isInteractive, + checked: color.isEqual(value), + disabled: props.disabled || !interactive, } } return { - isDragging, - isOpen, + dragging, + open, valueAsString, value, - open() { - send({ type: "OPEN" }) - }, - close() { - send({ type: "CLOSE" }) + setOpen(_open) { + if (_open === open) return + send({ type: _open ? "OPEN" : "CLOSE" }) }, setValue(value) { send({ type: "VALUE.SET", value: normalizeColor(value), src: "set-color" }) @@ -99,7 +96,7 @@ export function connect(state: State, send: Send, normalize ...parts.root.attrs, dir: state.context.dir, id: dom.getRootId(state.context), - "data-disabled": dataAttr(isDisabled), + "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(state.context.readOnly), style: { "--value": value.toString("css"), @@ -111,9 +108,9 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, id: dom.getLabelId(state.context), htmlFor: dom.getHiddenInputId(state.context), - "data-disabled": dataAttr(isDisabled), + "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(state.context.readOnly), - "data-focus": dataAttr(isFocused), + "data-focus": dataAttr(focused), onClick(event) { event.preventDefault() const inputEl = query(dom.getControlEl(state.context), "[data-channel=hex]") @@ -125,33 +122,33 @@ export function connect(state: State, send: Send, normalize ...parts.control.attrs, id: dom.getControlId(state.context), dir: state.context.dir, - "data-disabled": dataAttr(isDisabled), + "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(state.context.readOnly), - "data-state": isOpen ? "open" : "closed", - "data-focus": dataAttr(isFocused), + "data-state": open ? "open" : "closed", + "data-focus": dataAttr(focused), }), triggerProps: normalize.button({ ...parts.trigger.attrs, id: dom.getTriggerId(state.context), dir: state.context.dir, - disabled: isDisabled, + disabled: disabled, "aria-label": `select color. current color is ${valueAsString}`, "aria-controls": dom.getContentId(state.context), "aria-labelledby": dom.getLabelId(state.context), - "data-disabled": dataAttr(isDisabled), + "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(state.context.readOnly), "data-placement": currentPlacement, - "aria-expanded": dataAttr(isOpen), - "data-state": isOpen ? "open" : "closed", - "data-focus": dataAttr(isFocused), + "aria-expanded": dataAttr(open), + "data-state": open ? "open" : "closed", + "data-focus": dataAttr(focused), type: "button", onClick() { - if (!isInteractive) return + if (!interactive) return send({ type: "TRIGGER.CLICK" }) }, onBlur() { - if (!isInteractive) return + if (!interactive) return send({ type: "TRIGGER.BLUR" }) }, style: { @@ -171,8 +168,8 @@ export function connect(state: State, send: Send, normalize id: dom.getContentId(state.context), dir: state.context.dir, "data-placement": currentPlacement, - "data-state": isOpen ? "open" : "closed", - hidden: !isOpen, + "data-state": open ? "open" : "closed", + hidden: !open, }), getAreaProps(props = {}) { @@ -188,7 +185,7 @@ export function connect(state: State, send: Send, normalize id: dom.getAreaId(state.context), role: "group", onPointerDown(event) { - if (!isInteractive) return + if (!interactive) return const evt = getNativeEvent(event) if (!isLeftClick(evt) || isModifierKey(evt)) return @@ -242,8 +239,8 @@ export function connect(state: State, send: Send, normalize ...parts.areaThumb.attrs, id: dom.getAreaThumbId(state.context), dir: state.context.dir, - tabIndex: isDisabled ? undefined : 0, - "data-disabled": dataAttr(isDisabled), + tabIndex: disabled ? undefined : 0, + "data-disabled": dataAttr(disabled), role: "slider", "aria-valuemin": 0, "aria-valuemax": 100, @@ -261,12 +258,12 @@ export function connect(state: State, send: Send, normalize background: areaValue.withChannelValue("alpha", 1).toString("css"), }, onFocus() { - if (!isInteractive) return + if (!interactive) return send({ type: "AREA.FOCUS", id: "area", channel }) }, onKeyDown(event) { if (event.defaultPrevented) return - if (!isInteractive) return + if (!interactive) return const step = getEventStep(event) @@ -331,7 +328,7 @@ export function connect(state: State, send: Send, normalize "data-orientation": orientation, role: "presentation", onPointerDown(event) { - if (!isInteractive) return + if (!interactive) return const evt = getNativeEvent(event) if (!isLeftClick(evt) || isModifierKey(evt)) return @@ -387,11 +384,11 @@ export function connect(state: State, send: Send, normalize id: dom.getChannelSliderThumbId(state.context, channel), role: "slider", "aria-label": channel, - tabIndex: isDisabled ? undefined : 0, + tabIndex: disabled ? undefined : 0, "data-channel": channel, - "data-disabled": dataAttr(isDisabled), + "data-disabled": dataAttr(disabled), "data-orientation": orientation, - "aria-disabled": dataAttr(isDisabled), + "aria-disabled": dataAttr(disabled), "aria-orientation": orientation, "aria-valuemax": maxValue, "aria-valuemin": minValue, @@ -404,12 +401,12 @@ export function connect(state: State, send: Send, normalize ...placementStyles, }, onFocus() { - if (!isInteractive) return + if (!interactive) return send({ type: "CHANNEL_SLIDER.FOCUS", channel }) }, onKeyDown(event) { if (event.defaultPrevented) return - if (!isInteractive) return + if (!interactive) return const step = getEventStep(event) * stepValue @@ -466,33 +463,33 @@ export function connect(state: State, send: Send, normalize "aria-label": channel, spellCheck: false, autoComplete: "off", - disabled: isDisabled, - "data-disabled": dataAttr(isDisabled), + disabled: disabled, + "data-disabled": dataAttr(disabled), readOnly: state.context.readOnly, defaultValue: getChannelValue(value, channel), min: range?.minValue, max: range?.maxValue, step: range?.step, onBeforeInput(event) { - if (isTextField || !isInteractive) return + if (isTextField || !interactive) return const value = event.currentTarget.value if (value.match(/[^0-9.]/g)) { event.preventDefault() } }, onFocus(event) { - if (!isInteractive) return + if (!interactive) return send({ type: "CHANNEL_INPUT.FOCUS", channel }) event.target.select() }, onBlur(event) { - if (!isInteractive) return + if (!interactive) return const value = isTextField ? event.currentTarget.value : event.currentTarget.valueAsNumber send({ type: "CHANNEL_INPUT.BLUR", channel, value, isTextField }) }, onKeyDown(event) { if (event.defaultPrevented) return - if (!isInteractive) return + if (!interactive) return if (event.key === "Enter") { const value = isTextField ? event.currentTarget.value : event.currentTarget.valueAsNumber send({ type: "CHANNEL_INPUT.CHANGE", channel, value, isTextField }) @@ -509,7 +506,7 @@ export function connect(state: State, send: Send, normalize hiddenInputProps: normalize.input({ type: "text", - disabled: isDisabled, + disabled: disabled, name: state.context.name, id: dom.getHiddenInputId(state.context), style: visuallyHiddenStyle, @@ -520,11 +517,11 @@ export function connect(state: State, send: Send, normalize ...parts.eyeDropperTrigger.attrs, type: "button", dir: state.context.dir, - disabled: isDisabled, - "data-disabled": dataAttr(isDisabled), + disabled: disabled, + "data-disabled": dataAttr(disabled), "aria-label": "Pick a color from the screen", onClick() { - if (!isInteractive) return + if (!interactive) return send("EYEDROPPER.CLICK") }, }), @@ -540,15 +537,15 @@ export function connect(state: State, send: Send, normalize const triggerState = getSwatchTriggerState(props) return normalize.button({ ...parts.swatchTrigger.attrs, - disabled: triggerState.isDisabled, + disabled: triggerState.disabled, dir: state.context.dir, type: "button", "aria-label": `select ${triggerState.valueAsString} as the color`, - "data-state": triggerState.isChecked ? "checked" : "unchecked", + "data-state": triggerState.checked ? "checked" : "unchecked", "data-value": triggerState.valueAsString, - "data-disabled": dataAttr(triggerState.isDisabled), + "data-disabled": dataAttr(triggerState.disabled), onClick() { - if (triggerState.isDisabled) return + if (triggerState.disabled) return send({ type: "SWATCH_TRIGGER.CLICK", value: triggerState.value }) }, style: { @@ -562,7 +559,7 @@ export function connect(state: State, send: Send, normalize return normalize.element({ ...parts.swatchIndicator.attrs, dir: state.context.dir, - hidden: !triggerState.isChecked, + hidden: !triggerState.checked, }) }, @@ -572,7 +569,7 @@ export function connect(state: State, send: Send, normalize return normalize.element({ ...parts.swatch.attrs, dir: state.context.dir, - "data-state": triggerState.isChecked ? "checked" : "unchecked", + "data-state": triggerState.checked ? "checked" : "unchecked", "data-value": triggerState.valueAsString, style: { position: "relative", @@ -598,7 +595,7 @@ export function connect(state: State, send: Send, normalize "aria-label": "change color format", dir: state.context.dir, defaultValue: state.context.format, - disabled: isDisabled, + disabled: disabled, onChange(event) { const format = assertFormat(event.currentTarget.value) send({ type: "FORMAT.SET", format, src: "format-select" }) diff --git a/packages/machines/color-picker/src/color-picker.machine.ts b/packages/machines/color-picker/src/color-picker.machine.ts index b0a1d271fa..4bb0f1a20f 100644 --- a/packages/machines/color-picker/src/color-picker.machine.ts +++ b/packages/machines/color-picker/src/color-picker.machine.ts @@ -404,11 +404,11 @@ export function machine(userContext: UserDefinedContext) { openEyeDropper(ctx) { const isSupported = "EyeDropper" in dom.getWin(ctx) if (!isSupported) return - const win = dom.getWin(ctx) as any + const win = dom.getWin(ctx) const picker = new win.EyeDropper() picker .open() - .then(({ sRGBHex }: { sRGBHex: string }) => { + .then(({ sRGBHex }) => { const format = ctx.value.getFormat() const color = parseColor(sRGBHex).toFormat(format) as Color set.value(ctx, color) diff --git a/packages/machines/color-picker/src/color-picker.types.ts b/packages/machines/color-picker/src/color-picker.types.ts index d01e222427..c6dd65a700 100644 --- a/packages/machines/color-picker/src/color-picker.types.ts +++ b/packages/machines/color-picker/src/color-picker.types.ts @@ -7,6 +7,20 @@ import type { MaybeFunction } from "@zag-js/utils" export type ExtendedColorChannel = ColorChannel | "hex" | "css" +// patch the global window object to include the EyeDropper API + +interface EyeDropper { + new (): EyeDropper + open: (options?: { signal?: AbortSignal }) => Promise<{ sRGBHex: string }> + [Symbol.toStringTag]: "EyeDropper" +} + +declare global { + interface Window { + EyeDropper: EyeDropper + } +} + /* ----------------------------------------------------------------------------- * Callback details * -----------------------------------------------------------------------------*/ @@ -218,8 +232,8 @@ export interface SwatchTriggerProps { export interface SwatchTriggerState { value: Color valueAsString: string - isChecked: boolean - isDisabled: boolean + checked: boolean + disabled: boolean } export interface SwatchProps { @@ -241,11 +255,11 @@ export interface MachineApi { /** * Whether the color picker is being dragged */ - isDragging: boolean + dragging: boolean /** * Whether the color picker is open */ - isOpen: boolean + open: boolean /** * The current color value (as a string) */ @@ -283,13 +297,9 @@ export interface MachineApi { */ setAlpha(value: number): void /** - * Function to open the color picker - */ - open(): void - /** - * Function to close the color picker + * Function to open or close the color picker */ - close(): void + setOpen(open: boolean): void rootProps: T["element"] labelProps: T["element"] diff --git a/packages/machines/combobox/src/combobox.connect.ts b/packages/machines/combobox/src/combobox.connect.ts index c698c343e7..56bea6054a 100644 --- a/packages/machines/combobox/src/combobox.connect.ts +++ b/packages/machines/combobox/src/combobox.connect.ts @@ -11,7 +11,7 @@ import { getPlacementStyles } from "@zag-js/popper" import type { NormalizeProps, PropTypes } from "@zag-js/types" import { parts } from "./combobox.anatomy" import { dom } from "./combobox.dom" -import type { CollectionItem, ItemProps, MachineApi, Send, State } from "./combobox.types" +import type { CollectionItem, ItemProps, ItemState, MachineApi, Send, State } from "./combobox.types" export function connect( state: State, @@ -21,13 +21,13 @@ export function connect( const translations = state.context.translations const collection = state.context.collection - const isDisabled = state.context.disabled - const isInteractive = state.context.isInteractive - const isInvalid = state.context.invalid - const isReadOnly = state.context.readOnly + const disabled = state.context.disabled + const interactive = state.context.isInteractive + const invalid = state.context.invalid + const readOnly = state.context.readOnly - const isOpen = state.hasTag("open") - const isFocused = state.hasTag("focused") + const open = state.hasTag("open") + const focused = state.hasTag("focused") const isDialogPopup = state.context.popup === "dialog" const popperStyles = getPlacementStyles({ @@ -35,23 +35,23 @@ export function connect( placement: state.context.currentPlacement, }) - function getItemState(props: ItemProps) { + function getItemState(props: ItemProps): ItemState { const { item } = props const disabled = collection.isItemDisabled(item) const value = collection.itemToValue(item) return { value, - isDisabled: Boolean(disabled || isDisabled), - isHighlighted: state.context.highlightedValue === value, - isSelected: state.context.value.includes(value), + disabled: Boolean(disabled || disabled), + highlighted: state.context.highlightedValue === value, + selected: state.context.value.includes(value), } } return { - isFocused, - isOpen, + focused, + open, inputValue: state.context.inputValue, - isInputValueEmpty: state.context.isInputValueEmpty, + inputEmpty: state.context.isInputValueEmpty, highlightedValue: state.context.highlightedValue, highlightedItem: state.context.highlightedItem, value: state.context.value, @@ -87,21 +87,16 @@ export function connect( focus() { dom.getInputEl(state.context)?.focus() }, - open() { - if (isOpen) return - send("OPEN") + setOpen(_open) { + if (_open === open) return + send(_open ? "OPEN" : "CLOSE") }, - close() { - if (!isOpen) return - send("CLOSE") - }, - rootProps: normalize.element({ ...parts.root.attrs, dir: state.context.dir, id: dom.getRootId(state.context), - "data-invalid": dataAttr(isInvalid), - "data-readonly": dataAttr(isReadOnly), + "data-invalid": dataAttr(invalid), + "data-readonly": dataAttr(readOnly), }), labelProps: normalize.label({ @@ -109,10 +104,10 @@ export function connect( dir: state.context.dir, htmlFor: dom.getInputId(state.context), id: dom.getLabelId(state.context), - "data-readonly": dataAttr(isReadOnly), - "data-disabled": dataAttr(isDisabled), - "data-invalid": dataAttr(isInvalid), - "data-focus": dataAttr(isFocused), + "data-readonly": dataAttr(readOnly), + "data-disabled": dataAttr(disabled), + "data-invalid": dataAttr(invalid), + "data-focus": dataAttr(focused), onClick(event) { if (!isDialogPopup) return event.preventDefault() @@ -124,10 +119,10 @@ export function connect( ...parts.control.attrs, dir: state.context.dir, id: dom.getControlId(state.context), - "data-state": isOpen ? "open" : "closed", - "data-focus": dataAttr(isFocused), - "data-disabled": dataAttr(isDisabled), - "data-invalid": dataAttr(isInvalid), + "data-state": open ? "open" : "closed", + "data-focus": dataAttr(focused), + "data-disabled": dataAttr(disabled), + "data-invalid": dataAttr(invalid), }), positionerProps: normalize.element({ @@ -140,17 +135,17 @@ export function connect( inputProps: normalize.input({ ...parts.input.attrs, dir: state.context.dir, - "aria-invalid": ariaAttr(isInvalid), - "data-invalid": dataAttr(isInvalid), + "aria-invalid": ariaAttr(invalid), + "data-invalid": dataAttr(invalid), name: state.context.name, form: state.context.form, - disabled: isDisabled, + disabled: disabled, autoFocus: state.context.autoFocus, autoComplete: "off", autoCorrect: "off", autoCapitalize: "none", spellCheck: "false", - readOnly: isReadOnly, + readOnly: readOnly, placeholder: state.context.placeholder, id: dom.getInputId(state.context), type: "text", @@ -158,22 +153,22 @@ export function connect( defaultValue: state.context.inputValue, "aria-autocomplete": state.context.autoComplete ? "both" : "list", "aria-controls": isDialogPopup ? dom.getListId(state.context) : dom.getContentId(state.context), - "aria-expanded": isOpen, - "data-state": isOpen ? "open" : "closed", + "aria-expanded": open, + "data-state": open ? "open" : "closed", "aria-activedescendant": state.context.highlightedValue ? dom.getItemId(state.context, state.context.highlightedValue) : undefined, onClick() { if (!state.context.openOnClick) return - if (!isInteractive) return + if (!interactive) return send("INPUT.CLICK") }, onFocus() { - if (isDisabled) return + if (disabled) return send("INPUT.FOCUS") }, onBlur() { - if (isDisabled) return + if (disabled) return send("INPUT.BLUR") }, onChange(event) { @@ -181,7 +176,7 @@ export function connect( }, onKeyDown(event) { if (event.defaultPrevented) return - if (!isInteractive) return + if (!interactive) return const evt = getNativeEvent(event) if (evt.ctrlKey || evt.shiftKey || evt.isComposing) return @@ -192,33 +187,33 @@ export function connect( const keymap: EventKeyMap = { ArrowDown(event) { - if (!openOnKeyPress && !isOpen) return + if (!openOnKeyPress && !open) return send({ type: event.altKey ? "OPEN" : "INPUT.ARROW_DOWN", keypress }) event.preventDefault() }, ArrowUp() { - if (!openOnKeyPress && !isOpen) return + if (!openOnKeyPress && !open) return send({ type: event.altKey ? "CLOSE" : "INPUT.ARROW_UP", keypress }) event.preventDefault() }, Home(event) { if (isModifierKey) return send({ type: "INPUT.HOME", keypress }) - if (isOpen) { + if (open) { event.preventDefault() } }, End(event) { if (isModifierKey) return send({ type: "INPUT.END", keypress }) - if (isOpen) { + if (open) { event.preventDefault() } }, Enter(event) { if (evt.isComposing) return send({ type: "INPUT.ENTER", keypress }) - if (isOpen) { + if (open) { event.preventDefault() } const itemEl = dom.getHighlightedItemEl(state.context) @@ -244,20 +239,20 @@ export function connect( type: "button", tabIndex: isDialogPopup ? 0 : -1, "aria-label": translations.triggerLabel, - "aria-expanded": isOpen, - "data-state": isOpen ? "open" : "closed", - "aria-controls": isOpen ? dom.getContentId(state.context) : undefined, - disabled: isDisabled, - "data-readonly": dataAttr(isReadOnly), - "data-disabled": dataAttr(isDisabled), + "aria-expanded": open, + "data-state": open ? "open" : "closed", + "aria-controls": open ? dom.getContentId(state.context) : undefined, + disabled: disabled, + "data-readonly": dataAttr(readOnly), + "data-disabled": dataAttr(disabled), onClick(event) { const evt = getNativeEvent(event) - if (!isInteractive) return + if (!interactive) return if (!isLeftClick(evt)) return send("TRIGGER.CLICK") }, onPointerDown(event) { - if (!isInteractive) return + if (!interactive) return if (event.pointerType === "touch") return event.preventDefault() queueMicrotask(() => { @@ -301,8 +296,8 @@ export function connect( id: dom.getContentId(state.context), role: isDialogPopup ? "dialog" : "listbox", tabIndex: -1, - hidden: !isOpen, - "data-state": isOpen ? "open" : "closed", + hidden: !open, + "data-state": open ? "open" : "closed", "aria-labelledby": dom.getLabelId(state.context), "aria-multiselectable": state.context.multiple && !isDialogPopup ? true : undefined, onPointerDown(event) { @@ -324,12 +319,12 @@ export function connect( id: dom.getClearTriggerId(state.context), type: "button", tabIndex: -1, - disabled: isDisabled, + disabled: disabled, "aria-label": translations.clearTriggerLabel, "aria-controls": dom.getInputId(state.context), hidden: !state.context.value.length, onClick() { - if (!isInteractive) return + if (!interactive) return send({ type: "VALUE.CLEAR", src: "clear-trigger" }) }, }), @@ -346,19 +341,19 @@ export function connect( id: dom.getItemId(state.context, value), role: "option", tabIndex: -1, - "data-highlighted": dataAttr(itemState.isHighlighted), - "data-state": itemState.isSelected ? "checked" : "unchecked", - "aria-selected": itemState.isHighlighted, - "aria-disabled": itemState.isDisabled, - "data-disabled": dataAttr(itemState.isDisabled), + "data-highlighted": dataAttr(itemState.highlighted), + "data-state": itemState.selected ? "checked" : "unchecked", + "aria-selected": itemState.highlighted, + "aria-disabled": itemState.disabled, + "data-disabled": dataAttr(itemState.disabled), "data-value": itemState.value, onPointerMove() { - if (itemState.isDisabled) return + if (itemState.disabled) return send({ type: "ITEM.POINTER_MOVE", value }) }, onPointerLeave() { if (props.persistFocus) return - if (itemState.isDisabled) return + if (itemState.disabled) return const mouseMoved = state.previousEvent.type === "ITEM.POINTER_MOVE" if (!mouseMoved) return send({ type: "ITEM.POINTER_LEAVE", value }) @@ -367,7 +362,7 @@ export function connect( if (isDownloadingEvent(event)) return if (isOpeningInNewTab(event)) return if (isContextMenuEvent(event)) return - if (itemState.isDisabled) return + if (itemState.disabled) return send({ type: "ITEM.CLICK", src: "pointerup", value }) }, onTouchEnd(event) { @@ -383,8 +378,8 @@ export function connect( return normalize.element({ ...parts.itemText.attrs, dir: state.context.dir, - "data-disabled": dataAttr(itemState.isDisabled), - "data-highlighted": dataAttr(itemState.isHighlighted), + "data-disabled": dataAttr(itemState.disabled), + "data-highlighted": dataAttr(itemState.highlighted), }) }, getItemIndicatorProps(props) { @@ -393,8 +388,8 @@ export function connect( "aria-hidden": true, ...parts.itemIndicator.attrs, dir: state.context.dir, - "data-state": itemState.isSelected ? "checked" : "unchecked", - hidden: !itemState.isSelected, + "data-state": itemState.selected ? "checked" : "unchecked", + hidden: !itemState.selected, }) }, diff --git a/packages/machines/combobox/src/combobox.types.ts b/packages/machines/combobox/src/combobox.types.ts index 6bd495fac1..858b85e86c 100644 --- a/packages/machines/combobox/src/combobox.types.ts +++ b/packages/machines/combobox/src/combobox.types.ts @@ -278,15 +278,33 @@ export type Send = S.Send * -----------------------------------------------------------------------------*/ export interface ItemProps { + /** + * Whether hovering outside should clear the highlighted state + */ persistFocus?: boolean + /** + * The item to render + */ item: CollectionItem } export interface ItemState { + /** + * The value of the item + */ value: string - isDisabled: boolean - isSelected: boolean - isHighlighted: boolean + /** + * Whether the item is disabled + */ + disabled: boolean + /** + * Whether the item is selected + */ + selected: boolean + /** + * Whether the item is highlighted via pointer or keyboard navigation + */ + highlighted: boolean } export interface ItemGroupProps { @@ -301,15 +319,15 @@ export interface MachineApi(state: State, send: Send, normalize const disabled = state.context.disabled const readOnly = state.context.readOnly - const isInteractive = state.context.isInteractive + const interactive = state.context.isInteractive const min = state.context.min const max = state.context.max @@ -71,8 +71,8 @@ export function connect(state: State, send: Send, normalize const timeZone = state.context.timeZone const startOfWeek = state.context.startOfWeek - const isFocused = state.matches("focused") - const isOpen = state.matches("open") + const focused = state.matches("focused") + const open = state.matches("open") const isRangePicker = state.context.selectionMode === "range" const isDateUnavailableFn = state.context.isDateUnavailable @@ -120,12 +120,12 @@ export function connect(state: State, send: Send, normalize const { value, disabled } = props const normalized = focusedValue.set({ year: value }) const cellState = { - isFocused: focusedValue.year === props.value, - isSelectable: !isDateInvalid(normalized, min, max), - isSelected: !!selectedValue.find((date) => date.year === value), + focused: focusedValue.year === props.value, + selectable: !isDateInvalid(normalized, min, max), + selected: !!selectedValue.find((date) => date.year === value), valueText: value.toString(), - get isDisabled() { - return disabled || !cellState.isSelectable + get disabled() { + return disabled || !cellState.selectable }, } return cellState @@ -136,12 +136,12 @@ export function connect(state: State, send: Send, normalize const normalized = focusedValue.set({ month: value }) const formatter = getMonthFormatter(locale, timeZone) const cellState = { - isFocused: focusedValue.month === props.value, - isSelectable: !isDateInvalid(normalized, min, max), - isSelected: !!selectedValue.find((date) => date.month === value && date.year === focusedValue.year), + focused: focusedValue.month === props.value, + selectable: !isDateInvalid(normalized, min, max), + selected: !!selectedValue.find((date) => date.month === value && date.year === focusedValue.year), valueText: formatter.format(normalized.toDate(timeZone)), - get isDisabled() { - return disabled || !cellState.isSelectable + get disabled() { + return disabled || !cellState.selectable }, } return cellState @@ -156,28 +156,28 @@ export function connect(state: State, send: Send, normalize const end = visibleRange.start.add(unitDuration).subtract({ days: 1 }) const cellState = { - isInvalid: isDateInvalid(value, min, max), - isDisabled: disabled || isDateDisabled(value, visibleRange.start, end, min, max), - isSelected: selectedValue.some((date) => isDateEqual(value, date)), - isUnavailable: isDateUnavailable(value, isDateUnavailableFn, locale, min, max) && !disabled, - isOutsideRange: isDateOutsideVisibleRange(value, visibleRange.start, end), - isInRange: + invalid: isDateInvalid(value, min, max), + disabled: disabled || isDateDisabled(value, visibleRange.start, end, min, max), + selected: selectedValue.some((date) => isDateEqual(value, date)), + unavailable: isDateUnavailable(value, isDateUnavailableFn, locale, min, max) && !disabled, + outsideRange: isDateOutsideVisibleRange(value, visibleRange.start, end), + inRange: isRangePicker && (isDateWithinRange(value, selectedValue) || isDateWithinRange(value, hoveredRangeValue)), - isFirstInRange: isRangePicker && isDateEqual(value, selectedValue[0]), - isLastInRange: isRangePicker && isDateEqual(value, selectedValue[1]), - isToday: isTodayDate(value, timeZone), - isWeekend: isWeekend(value, locale), + firstInRange: isRangePicker && isDateEqual(value, selectedValue[0]), + lastInRange: isRangePicker && isDateEqual(value, selectedValue[1]), + today: isTodayDate(value, timeZone), + weekend: isWeekend(value, locale), formattedDate: formatter.format(value.toDate(timeZone)), - get isFocused() { - return isDateEqual(value, focusedValue) && !cellState.isOutsideRange + get focused() { + return isDateEqual(value, focusedValue) && !cellState.outsideRange }, get ariaLabel() { - if (cellState.isUnavailable) return `Not available. ${cellState.formattedDate}` - if (cellState.isSelected) return `Selected date. ${cellState.formattedDate}` + if (cellState.unavailable) return `Not available. ${cellState.formattedDate}` + if (cellState.selected) return `Selected date. ${cellState.formattedDate}` return `Choose ${cellState.formattedDate}` }, - get isSelectable() { - return !cellState.isDisabled && !cellState.isUnavailable + get selectable() { + return !cellState.disabled && !cellState.unavailable }, } return cellState @@ -189,8 +189,8 @@ export function connect(state: State, send: Send, normalize } return { - isFocused, - isOpen, + focused, + open, view: state.context.view, getRangePresetValue(preset) { return getDateRangePreset(preset, locale, timeZone) @@ -231,11 +231,9 @@ export function connect(state: State, send: Send, normalize setFocusedValue(value) { send({ type: "FOCUS.SET", value }) }, - open() { - send("OPEN") - }, - close() { - send("CLOSE") + setOpen(_open) { + if (_open === open) return + send(_open ? "OPEN" : "CLOSE") }, focusMonth, focusYear, @@ -270,7 +268,7 @@ export function connect(state: State, send: Send, normalize ...parts.root.attrs, dir: state.context.dir, id: dom.getRootId(state.context), - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(readOnly), }), @@ -279,7 +277,7 @@ export function connect(state: State, send: Send, normalize ...parts.label.attrs, dir: state.context.dir, htmlFor: dom.getInputId(state.context, 0), - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(readOnly), }), @@ -298,9 +296,9 @@ export function connect(state: State, send: Send, normalize contentProps: normalize.element({ ...parts.content.attrs, - hidden: !isOpen, + hidden: !open, dir: state.context.dir, - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", "data-placement": currentPlacement, id: dom.getContentId(state.context), role: "application", @@ -425,10 +423,10 @@ export function connect(state: State, send: Send, normalize return normalize.element({ ...parts.tableCell.attrs, role: "gridcell", - "aria-disabled": ariaAttr(!cellState.isSelectable), - "aria-selected": cellState.isSelected || cellState.isInRange, - "aria-invalid": ariaAttr(cellState.isInvalid), - "aria-current": cellState.isToday ? "date" : undefined, + "aria-disabled": ariaAttr(!cellState.selectable), + "aria-selected": cellState.selected || cellState.inRange, + "aria-invalid": ariaAttr(cellState.invalid), + "aria-current": cellState.today ? "date" : undefined, "data-value": value.toString(), }) }, @@ -440,28 +438,29 @@ export function connect(state: State, send: Send, normalize id: dom.getCellTriggerId(state.context, value.toString()), role: "button", dir: state.context.dir, - tabIndex: cellState.isFocused ? 0 : -1, + tabIndex: cellState.focused ? 0 : -1, "aria-label": cellState.ariaLabel, - "aria-disabled": ariaAttr(!cellState.isSelectable), - "aria-invalid": ariaAttr(cellState.isInvalid), - "data-disabled": dataAttr(!cellState.isSelectable), - "data-selected": dataAttr(cellState.isSelected), + "aria-disabled": ariaAttr(!cellState.selectable), + "aria-invalid": ariaAttr(cellState.invalid), + "data-disabled": dataAttr(!cellState.selectable), + "data-selected": dataAttr(cellState.selected), "data-value": value.toString(), "data-view": "day", - "data-today": dataAttr(cellState.isToday), - "data-focused": dataAttr(cellState.isFocused), - "data-unavailable": dataAttr(cellState.isUnavailable), - "data-range-start": dataAttr(cellState.isFirstInRange), - "data-range-end": dataAttr(cellState.isLastInRange), - "data-in-range": dataAttr(cellState.isInRange), - "data-outside-range": dataAttr(cellState.isOutsideRange), - "data-weekend": dataAttr(cellState.isWeekend), - onClick() { - if (!cellState.isSelectable) return + "data-today": dataAttr(cellState.today), + "data-focused": dataAttr(cellState.focused), + "data-unavailable": dataAttr(cellState.unavailable), + "data-range-start": dataAttr(cellState.firstInRange), + "data-range-end": dataAttr(cellState.lastInRange), + "data-in-range": dataAttr(cellState.inRange), + "data-outside-range": dataAttr(cellState.outsideRange), + "data-weekend": dataAttr(cellState.weekend), + onClick(event) { + if (event.defaultPrevented) return + if (!cellState.selectable) return send({ type: "CELL.CLICK", cell: "day", value }) }, onPointerMove(event) { - if (event.pointerType === "touch" || !cellState.isSelectable) return + if (event.pointerType === "touch" || !cellState.selectable) return const focus = event.currentTarget.ownerDocument.activeElement !== event.currentTarget if (hoveredValue && isEqualDay(value, hoveredValue)) return send({ type: "CELL.POINTER_MOVE", cell: "day", value, focus }) @@ -478,9 +477,9 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, colSpan: columns, role: "gridcell", - "aria-selected": ariaAttr(cellState.isSelected), - "data-selected": dataAttr(cellState.isSelected), - "aria-disabled": ariaAttr(!cellState.isSelectable), + "aria-selected": ariaAttr(cellState.selected), + "data-selected": dataAttr(cellState.selected), + "aria-disabled": ariaAttr(!cellState.selectable), "data-value": value, }) }, @@ -492,16 +491,17 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, role: "button", id: dom.getCellTriggerId(state.context, value.toString()), - "data-selected": dataAttr(cellState.isSelected), - "aria-disabled": ariaAttr(!cellState.isSelectable), - "data-disabled": dataAttr(!cellState.isSelectable), - "data-focused": dataAttr(cellState.isFocused), + "data-selected": dataAttr(cellState.selected), + "aria-disabled": ariaAttr(!cellState.selectable), + "data-disabled": dataAttr(!cellState.selectable), + "data-focused": dataAttr(cellState.focused), "aria-label": cellState.valueText, "data-view": "month", "data-value": value, - tabIndex: cellState.isFocused ? 0 : -1, - onClick() { - if (!cellState.isSelectable) return + tabIndex: cellState.focused ? 0 : -1, + onClick(event) { + if (event.defaultPrevented) return + if (!cellState.selectable) return send({ type: "CELL.CLICK", cell: "month", value }) }, }) @@ -516,9 +516,9 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, colSpan: columns, role: "gridcell", - "aria-selected": ariaAttr(cellState.isSelected), - "data-selected": dataAttr(cellState.isSelected), - "aria-disabled": ariaAttr(!cellState.isSelectable), + "aria-selected": ariaAttr(cellState.selected), + "data-selected": dataAttr(cellState.selected), + "aria-disabled": ariaAttr(!cellState.selectable), "data-value": value, }) }, @@ -530,16 +530,17 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, role: "button", id: dom.getCellTriggerId(state.context, value.toString()), - "data-selected": dataAttr(cellState.isSelected), - "data-focused": dataAttr(cellState.isFocused), - "aria-disabled": ariaAttr(!cellState.isSelectable), - "data-disabled": dataAttr(!cellState.isSelectable), + "data-selected": dataAttr(cellState.selected), + "data-focused": dataAttr(cellState.focused), + "aria-disabled": ariaAttr(!cellState.selectable), + "data-disabled": dataAttr(!cellState.selectable), "aria-label": cellState.valueText, "data-value": value, "data-view": "year", - tabIndex: cellState.isFocused ? 0 : -1, - onClick() { - if (!cellState.isSelectable) return + tabIndex: cellState.focused ? 0 : -1, + onClick(event) { + if (event.defaultPrevented) return + if (!cellState.selectable) return send({ type: "CELL.CLICK", cell: "year", value }) }, }) @@ -554,7 +555,8 @@ export function connect(state: State, send: Send, normalize type: "button", "aria-label": getNextTriggerLabel(view), disabled: disabled || !state.context.isNextVisibleRangeValid, - onClick() { + onClick(event) { + if (event.defaultPrevented) return send({ type: "GOTO.NEXT", view }) }, }) @@ -569,7 +571,8 @@ export function connect(state: State, send: Send, normalize type: "button", "aria-label": getPrevTriggerLabel(view), disabled: disabled || !state.context.isPrevVisibleRangeValid, - onClick() { + onClick(event) { + if (event.defaultPrevented) return send({ type: "GOTO.PREV", view }) }, }) @@ -582,7 +585,8 @@ export function connect(state: State, send: Send, normalize type: "button", "aria-label": "Clear dates", hidden: !state.context.value.length, - onClick() { + onClick(event) { + if (event.defaultPrevented) return send("VALUE.CLEAR") }, }), @@ -593,13 +597,14 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, type: "button", "data-placement": currentPlacement, - "aria-label": isOpen ? "Close calendar" : "Open calendar", + "aria-label": open ? "Close calendar" : "Open calendar", "aria-controls": dom.getContentId(state.context), - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", "aria-haspopup": "grid", disabled, - onClick() { - if (!isInteractive) return + onClick(event) { + if (event.defaultPrevented) return + if (!interactive) return send("TRIGGER.CLICK") }, }), @@ -614,8 +619,9 @@ export function connect(state: State, send: Send, normalize type: "button", disabled, "aria-label": getViewTriggerLabel(state.context.view), - onClick() { - if (!isInteractive) return + onClick(event) { + if (event.defaultPrevented) return + if (!interactive) return send("VIEW.CHANGE") }, }) @@ -641,7 +647,7 @@ export function connect(state: State, send: Send, normalize spellCheck: "false", dir: state.context.dir, name: state.context.name, - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", readOnly, disabled, placeholder: getInputPlaceholder(locale), @@ -660,7 +666,7 @@ export function connect(state: State, send: Send, normalize }, onKeyDown(event) { if (event.defaultPrevented) return - if (!isInteractive) return + if (!interactive) return const evt = getNativeEvent(event) if (evt.isComposing) return if (event.key !== "Enter") return @@ -714,7 +720,8 @@ export function connect(state: State, send: Send, normalize ? `select ${value[0].toString()} to ${value[1].toString()}` : `select ${value}`, type: "button", - onClick() { + onClick(event) { + if (event.defaultPrevented) return send({ type: "PRESET.CLICK", value }) }, }) diff --git a/packages/machines/date-picker/src/date-picker.types.ts b/packages/machines/date-picker/src/date-picker.types.ts index 1a8c502a61..d816ab6d36 100644 --- a/packages/machines/date-picker/src/date-picker.types.ts +++ b/packages/machines/date-picker/src/date-picker.types.ts @@ -317,11 +317,11 @@ export interface TableCellProps { } export interface TableCellState { - isFocused: boolean - isSelectable: boolean - isSelected: boolean + focused: boolean + selectable: boolean + selected: boolean valueText: string - readonly isDisabled: boolean + readonly disabled: boolean } export interface DayTableCellProps { @@ -331,20 +331,20 @@ export interface DayTableCellProps { } export interface DayTableCellState { - isInvalid: boolean - isDisabled: boolean - isSelected: boolean - isUnavailable: boolean - isOutsideRange: boolean - isInRange: boolean - isFirstInRange: boolean - isLastInRange: boolean - isToday: boolean - isWeekend: boolean + invalid: boolean + disabled: boolean + selected: boolean + unavailable: boolean + outsideRange: boolean + inRange: boolean + firstInRange: boolean + lastInRange: boolean + today: boolean + weekend: boolean formattedDate: string - readonly isFocused: boolean + readonly focused: boolean readonly ariaLabel: string - readonly isSelectable: boolean + readonly selectable: boolean } export interface TableProps { @@ -402,11 +402,11 @@ export interface MachineApi { /** * Whether the input is focused */ - isFocused: boolean + focused: boolean /** * Whether the date picker is open */ - isOpen: boolean + open: boolean /** * The current view of the date picker */ @@ -488,13 +488,9 @@ export interface MachineApi { */ clearValue(): void /** - * Function to open the calendar. - */ - open(): void - /** - * Function to close the calendar. + * Function to open or close the calendar. */ - close(): void + setOpen(open: boolean): void /** * Function to set the selected month. */ diff --git a/packages/machines/dialog/src/dialog.connect.ts b/packages/machines/dialog/src/dialog.connect.ts index 9debea931b..1aa91cf736 100644 --- a/packages/machines/dialog/src/dialog.connect.ts +++ b/packages/machines/dialog/src/dialog.connect.ts @@ -5,16 +5,14 @@ import type { MachineApi, Send, State } from "./dialog.types" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { const ariaLabel = state.context["aria-label"] - const isOpen = state.matches("open") + const open = state.matches("open") const rendered = state.context.renderedElements return { - isOpen, - open() { - send("OPEN") - }, - close() { - send("CLOSE") + open, + setOpen(_open) { + if (_open === open) return + send(_open ? "OPEN" : "CLOSE") }, triggerProps: normalize.button({ @@ -23,10 +21,11 @@ export function connect(state: State, send: Send, normalize id: dom.getTriggerId(state.context), "aria-haspopup": "dialog", type: "button", - "aria-expanded": isOpen, - "data-state": isOpen ? "open" : "closed", + "aria-expanded": open, + "data-state": open ? "open" : "closed", "aria-controls": dom.getContentId(state.context), - onClick() { + onClick(event) { + if (event.defaultPrevented) return send("TOGGLE") }, }), @@ -34,9 +33,9 @@ export function connect(state: State, send: Send, normalize backdropProps: normalize.element({ ...parts.backdrop.attrs, dir: state.context.dir, - hidden: !isOpen, + hidden: !open, id: dom.getBackdropId(state.context), - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", }), positionerProps: normalize.element({ @@ -44,7 +43,7 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, id: dom.getPositionerId(state.context), style: { - pointerEvents: isOpen ? undefined : "none", + pointerEvents: open ? undefined : "none", }, }), @@ -52,10 +51,10 @@ export function connect(state: State, send: Send, normalize ...parts.content.attrs, dir: state.context.dir, role: state.context.role, - hidden: !isOpen, + hidden: !open, id: dom.getContentId(state.context), tabIndex: -1, - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", "aria-modal": true, "aria-label": ariaLabel || undefined, "aria-labelledby": ariaLabel || !rendered.title ? undefined : dom.getTitleId(state.context), @@ -80,6 +79,7 @@ export function connect(state: State, send: Send, normalize id: dom.getCloseTriggerId(state.context), type: "button", onClick(event) { + if (event.defaultPrevented) return event.stopPropagation() send("CLOSE") }, diff --git a/packages/machines/dialog/src/dialog.types.ts b/packages/machines/dialog/src/dialog.types.ts index afbe63ba6e..47b30de38f 100644 --- a/packages/machines/dialog/src/dialog.types.ts +++ b/packages/machines/dialog/src/dialog.types.ts @@ -121,15 +121,11 @@ export interface MachineApi { /** * Whether the dialog is open */ - isOpen: boolean - /** - * Function to open the dialog - */ - open(): void + open: boolean /** - * Function to close the dialog + * Function to open or close the dialog */ - close(): void + setOpen(open: boolean): void triggerProps: T["button"] backdropProps: T["element"] diff --git a/packages/machines/editable/src/editable.connect.ts b/packages/machines/editable/src/editable.connect.ts index 51fb7544fa..8df6febf9d 100644 --- a/packages/machines/editable/src/editable.connect.ts +++ b/packages/machines/editable/src/editable.connect.ts @@ -6,24 +6,24 @@ import { dom } from "./editable.dom" import type { MachineApi, Send, State } from "./editable.types" export function connect
{api.type === "loading" && } {api.title} @@ -39,7 +26,7 @@ function ToastItem({ actor }: { actor: toast.Service }) { - +
{{ state.value }}
{api().type === "loading" && } {api().title} diff --git a/examples/solid-ts/src/pages/tooltip.tsx b/examples/solid-ts/src/pages/tooltip.tsx index cf003e2a6c..2d1c53080e 100644 --- a/examples/solid-ts/src/pages/tooltip.tsx +++ b/examples/solid-ts/src/pages/tooltip.tsx @@ -20,7 +20,7 @@ export default function Page() { Hover me - + @@ -34,7 +34,7 @@ export default function Page() { Over me - + diff --git a/examples/svelte-ts/package.json b/examples/svelte-ts/package.json index 9dc0c8c1af..9c8874415d 100644 --- a/examples/svelte-ts/package.json +++ b/examples/svelte-ts/package.json @@ -79,7 +79,6 @@ "@zag-js/tree-view": "workspace:*", "@zag-js/types": "workspace:*", "@zag-js/utils": "workspace:*", - "@zag-js/visually-hidden": "workspace:*", "form-serialize": "0.7.2", "match-sorter": "6.3.4", "lucide-svelte": "0.372.0", diff --git a/examples/svelte-ts/src/lib/components/toast-item.svelte b/examples/svelte-ts/src/lib/components/toast-item.svelte index 4defff7ff5..a3a23cd578 100644 --- a/examples/svelte-ts/src/lib/components/toast-item.svelte +++ b/examples/svelte-ts/src/lib/components/toast-item.svelte @@ -1,6 +1,7 @@ - - - {api.title} - {api.description} - Close - + + + {api.title} + {api.description} + + + + diff --git a/examples/svelte-ts/src/routes/accordion.svelte b/examples/svelte-ts/src/routes/accordion.svelte index 1ad9cf8e5f..155564898b 100644 --- a/examples/svelte-ts/src/routes/accordion.svelte +++ b/examples/svelte-ts/src/routes/accordion.svelte @@ -9,11 +9,11 @@ const controls = useControls(accordionControls) - const [_state, send] = useMachine(accordion.machine({ id: "1" }), { + const [snapshot, send] = useMachine(accordion.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(accordion.connect(_state, send, normalizeProps)) + const api = $derived(accordion.connect(snapshot, send, normalizeProps)) @@ -38,5 +38,5 @@ - + diff --git a/examples/svelte-ts/src/routes/avatar.svelte b/examples/svelte-ts/src/routes/avatar.svelte index 85f47bb29b..7f8e9d00e0 100644 --- a/examples/svelte-ts/src/routes/avatar.svelte +++ b/examples/svelte-ts/src/routes/avatar.svelte @@ -11,8 +11,8 @@ let src = $state(images[0]) let showImage = $state(true) - const [_state, send] = useMachine(avatar.machine({ id: "1" })) - const api = $derived(avatar.connect(_state, send, normalizeProps)) + const [snapshot, send] = useMachine(avatar.machine({ id: "1" })) + const api = $derived(avatar.connect(snapshot, send, normalizeProps)) @@ -31,5 +31,5 @@ - + diff --git a/examples/svelte-ts/src/routes/carousel.svelte b/examples/svelte-ts/src/routes/carousel.svelte index 56d238d2f1..cf168d6005 100644 --- a/examples/svelte-ts/src/routes/carousel.svelte +++ b/examples/svelte-ts/src/routes/carousel.svelte @@ -8,11 +8,11 @@ const controls = useControls(carouselControls) - const [_state, send] = useMachine(carousel.machine({ id: "1", index: 0, spacing: "20px", slidesPerView: 2 }), { + const [snapshot, send] = useMachine(carousel.machine({ id: "1", index: 0, spacing: "20px", slidesPerView: 2 }), { // context: controls.context, }) - const api = $derived(carousel.connect(_state, send, normalizeProps)) + const api = $derived(carousel.connect(snapshot, send, normalizeProps)) @@ -32,5 +32,5 @@ - + diff --git a/examples/svelte-ts/src/routes/checkbox.svelte b/examples/svelte-ts/src/routes/checkbox.svelte index 8066ec2d01..b6afdd4d5b 100644 --- a/examples/svelte-ts/src/routes/checkbox.svelte +++ b/examples/svelte-ts/src/routes/checkbox.svelte @@ -9,11 +9,11 @@ const controls = useControls(checkboxControls) - const [_state, send] = useMachine(checkbox.machine({ id: "1" }), { + const [snapshot, send] = useMachine(checkbox.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(checkbox.connect(_state, send, normalizeProps)) + const api = $derived(checkbox.connect(snapshot, send, normalizeProps)) @@ -25,19 +25,19 @@ > - - Input {api.isChecked ? "Checked" : "Unchecked"} + + Input {api.checked ? "Checked" : "Unchecked"} Indicator - api.setChecked(true)}>Check - api.setChecked(false)}>Uncheck + api.setChecked(true)}>Check + api.setChecked(false)}>Uncheck Reset Form - + diff --git a/examples/svelte-ts/src/routes/clipboard.svelte b/examples/svelte-ts/src/routes/clipboard.svelte index 0e8c2ca9d5..b738a8ade6 100644 --- a/examples/svelte-ts/src/routes/clipboard.svelte +++ b/examples/svelte-ts/src/routes/clipboard.svelte @@ -9,7 +9,7 @@ const controls = useControls(clipboardControls) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( clipboard.machine({ id: "1", value: "https://github/com/chakra-ui/zag", @@ -19,7 +19,7 @@ }, ) - const api = $derived(clipboard.connect(_state, send, normalizeProps)) + const api = $derived(clipboard.connect(snapshot, send, normalizeProps)) @@ -29,7 +29,7 @@ - {#if api.isCopied} + {#if api.copied} {:else} @@ -42,5 +42,5 @@ - + diff --git a/examples/svelte-ts/src/routes/collapsible.svelte b/examples/svelte-ts/src/routes/collapsible.svelte index f3dc09de4b..38213d6bba 100644 --- a/examples/svelte-ts/src/routes/collapsible.svelte +++ b/examples/svelte-ts/src/routes/collapsible.svelte @@ -8,11 +8,11 @@ const controls = useControls(collapsibleControls) - const [_state, send] = useMachine(collapsible.machine({ id: "1" }), { + const [snapshot, send] = useMachine(collapsible.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(collapsible.connect(_state, send, normalizeProps)) + const api = $derived(collapsible.connect(snapshot, send, normalizeProps)) @@ -31,11 +31,11 @@ Toggle Controls - Open - Close + api.setOpen(true)}>Open + api.setOpen(false)}>Close - + diff --git a/examples/svelte-ts/src/routes/color-picker.svelte b/examples/svelte-ts/src/routes/color-picker.svelte index 5f67febf57..8907223454 100644 --- a/examples/svelte-ts/src/routes/color-picker.svelte +++ b/examples/svelte-ts/src/routes/color-picker.svelte @@ -11,7 +11,7 @@ const controls = useControls(colorPickerControls) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( colorPicker.machine({ id: "1", name: "color", @@ -23,7 +23,7 @@ }, ) - const api = $derived(colorPicker.connect(_state, send, normalizeProps)) + const api = $derived(colorPicker.connect(snapshot, send, normalizeProps)) @@ -128,7 +128,7 @@ - + {#snippet EyeDropIcon()} diff --git a/examples/svelte-ts/src/routes/combobox.svelte b/examples/svelte-ts/src/routes/combobox.svelte index 911bc12e9b..3fb252f673 100644 --- a/examples/svelte-ts/src/routes/combobox.svelte +++ b/examples/svelte-ts/src/routes/combobox.svelte @@ -19,7 +19,7 @@ controls.setContext("collection", collection) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( combobox.machine({ id: "1", collection, @@ -39,7 +39,7 @@ }, ) - const api = $derived(combobox.connect(_state, send, normalizeProps)) + const api = $derived(combobox.connect(snapshot, send, normalizeProps)) $inspect(api.inputValue) @@ -71,5 +71,5 @@ - + diff --git a/examples/svelte-ts/src/routes/context-menu.svelte b/examples/svelte-ts/src/routes/context-menu.svelte index 8db193d270..7733fc7946 100644 --- a/examples/svelte-ts/src/routes/context-menu.svelte +++ b/examples/svelte-ts/src/routes/context-menu.svelte @@ -4,14 +4,14 @@ import * as menu from "@zag-js/menu" import { normalizeProps, portal, useMachine } from "@zag-js/svelte" - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( menu.machine({ id: "1", onSelect: console.log, }), ) - const api = $derived(menu.connect(_state, send, normalizeProps)) + const api = $derived(menu.connect(snapshot, send, normalizeProps)) @@ -27,5 +27,5 @@ - + diff --git a/examples/svelte-ts/src/routes/file-upload.svelte b/examples/svelte-ts/src/routes/file-upload.svelte index 17e4c44ae0..4d4fa1eea8 100644 --- a/examples/svelte-ts/src/routes/file-upload.svelte +++ b/examples/svelte-ts/src/routes/file-upload.svelte @@ -8,11 +8,11 @@ const controls = useControls(fileUploadControls) - const [state, send] = useMachine(fileUpload.machine({ id: "1" }), { + const [snapshot, send] = useMachine(fileUpload.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(fileUpload.connect(state, send, normalizeProps)) + const api = $derived(fileUpload.connect(snapshot, send, normalizeProps)) @@ -40,5 +40,5 @@ - + diff --git a/examples/svelte-ts/src/routes/floating-panel.svelte b/examples/svelte-ts/src/routes/floating-panel.svelte index 332450b06b..c6b14e79fa 100644 --- a/examples/svelte-ts/src/routes/floating-panel.svelte +++ b/examples/svelte-ts/src/routes/floating-panel.svelte @@ -9,11 +9,11 @@ const controls = useControls(floatingPanelControls) - const [_state, send] = useMachine(floatingPanel.machine({ id: "1" }), { + const [snapshot, send] = useMachine(floatingPanel.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(floatingPanel.connect(_state, send, normalizeProps)) + const api = $derived(floatingPanel.connect(snapshot, send, normalizeProps)) @@ -58,5 +58,5 @@ - + diff --git a/examples/svelte-ts/src/routes/hover-card.svelte b/examples/svelte-ts/src/routes/hover-card.svelte index ee8de30b40..0da60ac927 100644 --- a/examples/svelte-ts/src/routes/hover-card.svelte +++ b/examples/svelte-ts/src/routes/hover-card.svelte @@ -8,22 +8,22 @@ const controls = useControls(hoverCardControls) - const [state, send] = useMachine(hoverCard.machine({ id: "1" }), { + const [snapshot, send] = useMachine(hoverCard.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(hoverCard.connect(state, send, normalizeProps)) + const api = $derived(hoverCard.connect(snapshot, send, normalizeProps)) Twitter - {#if api.isOpen} + {#if api.open} - + Twitter Preview Twitter @@ -36,5 +36,5 @@ - + diff --git a/examples/svelte-ts/src/routes/menu-options.svelte b/examples/svelte-ts/src/routes/menu-options.svelte index ecb154336b..cabbc699b3 100644 --- a/examples/svelte-ts/src/routes/menu-options.svelte +++ b/examples/svelte-ts/src/routes/menu-options.svelte @@ -11,11 +11,11 @@ let order = $state("") let type = $state([]) - const [_state, send] = useMachine(menu.machine({ id: "1" }), { + const [snapshot, send] = useMachine(menu.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(menu.connect(_state, send, normalizeProps)) + const api = $derived(menu.connect(snapshot, send, normalizeProps)) const radios = $derived( menuOptionData.order.map((item) => ({ @@ -71,5 +71,5 @@ - + diff --git a/examples/svelte-ts/src/routes/menu.svelte b/examples/svelte-ts/src/routes/menu.svelte index 4459ccef1b..7d277a4db5 100644 --- a/examples/svelte-ts/src/routes/menu.svelte +++ b/examples/svelte-ts/src/routes/menu.svelte @@ -8,11 +8,11 @@ const controls = useControls(menuControls) - const [state, send] = useMachine(menu.machine({ id: "1", onSelect: console.log }), { + const [snapshot, send] = useMachine(menu.machine({ id: "1", onSelect: console.log }), { context: controls.context, }) - const api = $derived(menu.connect(state, send, normalizeProps)) + const api = $derived(menu.connect(snapshot, send, normalizeProps)) @@ -32,5 +32,5 @@ - + diff --git a/examples/svelte-ts/src/routes/number-input.svelte b/examples/svelte-ts/src/routes/number-input.svelte index 433145fd4d..71d8a9a347 100644 --- a/examples/svelte-ts/src/routes/number-input.svelte +++ b/examples/svelte-ts/src/routes/number-input.svelte @@ -8,16 +8,16 @@ const controls = useControls(numberInputControls) - const [_state, send] = useMachine(numberInput.machine({ id: "1" }), { + const [snapshot, send] = useMachine(numberInput.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(numberInput.connect(_state, send, normalizeProps)) + const api = $derived(numberInput.connect(snapshot, send, normalizeProps)) - + Enter number: @@ -29,5 +29,5 @@ - + diff --git a/examples/svelte-ts/src/routes/pagination.svelte b/examples/svelte-ts/src/routes/pagination.svelte index 18f3c426d9..7a8cf7b012 100644 --- a/examples/svelte-ts/src/routes/pagination.svelte +++ b/examples/svelte-ts/src/routes/pagination.svelte @@ -9,7 +9,7 @@ const controls = useControls(paginationControls) let details = $state({}) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( pagination.machine({ id: "1", count: paginationData.length, @@ -22,7 +22,7 @@ }, ) - const api = $derived(pagination.connect(_state, send, normalizeProps)) + const api = $derived(pagination.connect(snapshot, send, normalizeProps)) const data = $derived(api.slice(paginationData)) @@ -82,5 +82,5 @@ - + diff --git a/examples/svelte-ts/src/routes/pin-input.svelte b/examples/svelte-ts/src/routes/pin-input.svelte index eee5614dd5..4e6b2f7a5e 100644 --- a/examples/svelte-ts/src/routes/pin-input.svelte +++ b/examples/svelte-ts/src/routes/pin-input.svelte @@ -9,7 +9,7 @@ const controls = useControls(pinInputControls) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( pinInput.machine({ name: "test", id: "1", @@ -19,7 +19,7 @@ }, ) - const api = $derived(pinInput.connect(_state, send, normalizeProps)) + const api = $derived(pinInput.connect(snapshot, send, normalizeProps)) @@ -46,5 +46,5 @@ - + diff --git a/examples/svelte-ts/src/routes/popover.svelte b/examples/svelte-ts/src/routes/popover.svelte index f901b26b5b..1c0f5589fb 100644 --- a/examples/svelte-ts/src/routes/popover.svelte +++ b/examples/svelte-ts/src/routes/popover.svelte @@ -8,11 +8,11 @@ const controls = useControls(popoverControls) - const [state, send] = useMachine(popover.machine({ id: "1" }), { + const [snapshot, send] = useMachine(popover.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(popover.connect(state, send, normalizeProps)) + const api = $derived(popover.connect(snapshot, send, normalizeProps)) @@ -29,7 +29,7 @@ - + Popover Title @@ -48,5 +48,5 @@ - + diff --git a/examples/svelte-ts/src/routes/progress.svelte b/examples/svelte-ts/src/routes/progress.svelte index 4a4233940e..744cc5f177 100644 --- a/examples/svelte-ts/src/routes/progress.svelte +++ b/examples/svelte-ts/src/routes/progress.svelte @@ -8,11 +8,11 @@ const controls = useControls(progressControls) - const [_state, send] = useMachine(progress.machine({ id: "1" }), { + const [snapshot, send] = useMachine(progress.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(progress.connect(_state, send, normalizeProps)) + const api = $derived(progress.connect(snapshot, send, normalizeProps)) @@ -25,7 +25,7 @@ - + {api.valueAsString} @@ -39,5 +39,5 @@ - + diff --git a/examples/svelte-ts/src/routes/radio-group.svelte b/examples/svelte-ts/src/routes/radio-group.svelte index 76070535dd..111ab8046a 100644 --- a/examples/svelte-ts/src/routes/radio-group.svelte +++ b/examples/svelte-ts/src/routes/radio-group.svelte @@ -9,11 +9,11 @@ const controls = useControls(radioControls) - const [state, send] = useMachine(radio.machine({ id: "1", name: "fruit" }), { + const [snapshot, send] = useMachine(radio.machine({ id: "1", name: "fruit" }), { context: controls.context, }) - const api = $derived(radio.connect(state, send, normalizeProps)) + const api = $derived(radio.connect(snapshot, send, normalizeProps)) @@ -26,10 +26,10 @@ Fruits - + {#each radioData as opt} - + {opt.label} @@ -47,5 +47,5 @@ - + diff --git a/examples/svelte-ts/src/routes/range-slider.svelte b/examples/svelte-ts/src/routes/range-slider.svelte index 0213cab1b7..e091e846e4 100644 --- a/examples/svelte-ts/src/routes/range-slider.svelte +++ b/examples/svelte-ts/src/routes/range-slider.svelte @@ -9,7 +9,7 @@ const controls = useControls(sliderControls) - const [state, send] = useMachine( + const [snapshot, send] = useMachine( slider.machine({ id: "1", name: "quantity", @@ -18,7 +18,7 @@ { context: controls.context }, ) - const api = $derived(slider.connect(state, send, normalizeProps)) + const api = $derived(slider.connect(snapshot, send, normalizeProps)) @@ -37,7 +37,7 @@ - + {#each api.value as _, index} @@ -57,5 +57,5 @@ - + diff --git a/examples/svelte-ts/src/routes/rating-group.svelte b/examples/svelte-ts/src/routes/rating-group.svelte index 9eb49779cb..0b0b648801 100644 --- a/examples/svelte-ts/src/routes/rating-group.svelte +++ b/examples/svelte-ts/src/routes/rating-group.svelte @@ -8,11 +8,11 @@ const controls = useControls(ratingControls) - const [state, send] = useMachine(rating.machine({ id: "1", value: 2.5 }), { + const [snapshot, send] = useMachine(rating.machine({ id: "1", value: 2.5 }), { context: controls.context, }) - const api = $derived(rating.connect(state, send, normalizeProps)) + const api = $derived(rating.connect(snapshot, send, normalizeProps)) {#snippet HalfStar()} @@ -50,7 +50,7 @@ {#each api.items as index} {@const itemState = api.getItemState({ index })} - {#if itemState.isHalf} + {#if itemState.half} {@render HalfStar()} {:else} {@render Star()} @@ -65,5 +65,5 @@ - + diff --git a/examples/svelte-ts/src/routes/segment-control.svelte b/examples/svelte-ts/src/routes/segment-control.svelte index 09760f00c9..b0c0bdea9c 100644 --- a/examples/svelte-ts/src/routes/segment-control.svelte +++ b/examples/svelte-ts/src/routes/segment-control.svelte @@ -8,16 +8,16 @@ const controls = useControls(radioControls) - const [state, send] = useMachine(radio.machine({ id: "2", name: "fruit", orientation: "horizontal" }), { + const [snapshot, send] = useMachine(radio.machine({ id: "2", name: "fruit", orientation: "horizontal" }), { context: controls.context, }) - const api = $derived(radio.connect(state, send, normalizeProps)) + const api = $derived(radio.connect(snapshot, send, normalizeProps)) - + {#each radioData as opt} @@ -31,5 +31,5 @@ - + diff --git a/examples/svelte-ts/src/routes/select.svelte b/examples/svelte-ts/src/routes/select.svelte index c9ac118008..6c920ebcdd 100644 --- a/examples/svelte-ts/src/routes/select.svelte +++ b/examples/svelte-ts/src/routes/select.svelte @@ -9,7 +9,7 @@ const controls = useControls(selectControls) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( select.machine({ id: "1", name: "select", @@ -20,7 +20,7 @@ }, ) - const api = $derived(select.connect(_state, send, normalizeProps)) + const api = $derived(select.connect(snapshot, send, normalizeProps)) @@ -71,5 +71,5 @@ - + diff --git a/examples/svelte-ts/src/routes/signature-pad.svelte b/examples/svelte-ts/src/routes/signature-pad.svelte index 12cf0d019e..4682c3dc86 100644 --- a/examples/svelte-ts/src/routes/signature-pad.svelte +++ b/examples/svelte-ts/src/routes/signature-pad.svelte @@ -12,7 +12,7 @@ let url = $state("") const setUrl = (value: string) => (url = value) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( signaturePad.machine({ id: "1", onDrawEnd(details) { @@ -29,7 +29,7 @@ }, ) - const api = $derived(signaturePad.connect(_state, send, normalizeProps)) + const api = $derived(signaturePad.connect(snapshot, send, normalizeProps)) @@ -69,5 +69,5 @@ - + diff --git a/examples/svelte-ts/src/routes/slider.svelte b/examples/svelte-ts/src/routes/slider.svelte index af2fa2c5ba..2082542b29 100644 --- a/examples/svelte-ts/src/routes/slider.svelte +++ b/examples/svelte-ts/src/routes/slider.svelte @@ -9,7 +9,7 @@ const controls = useControls(sliderControls) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( slider.machine({ id: "1", name: "quantity", @@ -20,7 +20,7 @@ }, ) - const api = $derived(slider.connect(_state, send, normalizeProps)) + const api = $derived(slider.connect(snapshot, send, normalizeProps)) @@ -60,5 +60,5 @@ - + diff --git a/examples/svelte-ts/src/routes/switch.svelte b/examples/svelte-ts/src/routes/switch.svelte index 5b643b2708..dc497cfc5f 100644 --- a/examples/svelte-ts/src/routes/switch.svelte +++ b/examples/svelte-ts/src/routes/switch.svelte @@ -8,11 +8,11 @@ const controls = useControls(switchControls) - const [state, send] = useMachine(zagSwitch.machine({ id: "1", name: "switch" }), { + const [snapshot, send] = useMachine(zagSwitch.machine({ id: "1", name: "switch" }), { context: controls.context, }) - const api = $derived(zagSwitch.connect(state, send, normalizeProps)) + const api = $derived(zagSwitch.connect(snapshot, send, normalizeProps)) @@ -20,12 +20,12 @@ - + - Feature is {api.isChecked ? "enabled" : "disabled"} + Feature is {api.checked ? "enabled" : "disabled"} - + diff --git a/examples/svelte-ts/src/routes/tabs.svelte b/examples/svelte-ts/src/routes/tabs.svelte index f3419dab4c..9591f2505d 100644 --- a/examples/svelte-ts/src/routes/tabs.svelte +++ b/examples/svelte-ts/src/routes/tabs.svelte @@ -8,7 +8,7 @@ const controls = useControls(tabsControls) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( tabs.machine({ id: "1", value: "nils", @@ -18,12 +18,12 @@ }, ) - const api = $derived(tabs.connect(_state, send, normalizeProps)) + const api = $derived(tabs.connect(snapshot, send, normalizeProps)) - + {#each tabsData as data} @@ -44,5 +44,5 @@ - + diff --git a/examples/svelte-ts/src/routes/tags-input.svelte b/examples/svelte-ts/src/routes/tags-input.svelte index 1cfe03fef5..f832d7a26f 100644 --- a/examples/svelte-ts/src/routes/tags-input.svelte +++ b/examples/svelte-ts/src/routes/tags-input.svelte @@ -12,7 +12,7 @@ const controls = useControls(tagsInputControls) - const [_state, send] = useMachine( + const [snapshot, send] = useMachine( tagsInput.machine({ id: "1", value: ["React", "Vue"], @@ -22,7 +22,7 @@ }, ) - const api = $derived(tagsInput.connect(_state, send, normalizeProps)) + const api = $derived(tagsInput.connect(snapshot, send, normalizeProps)) @@ -54,5 +54,5 @@ - + diff --git a/examples/svelte-ts/src/routes/toast.svelte b/examples/svelte-ts/src/routes/toast.svelte index 44d5a1bbe1..97f11649ff 100644 --- a/examples/svelte-ts/src/routes/toast.svelte +++ b/examples/svelte-ts/src/routes/toast.svelte @@ -9,7 +9,7 @@ const controls = useControls(toastControls) - const [state, send] = useMachine( + const [snapshot, send] = useMachine( toast.group.machine({ id: "1", placement: "bottom-end", @@ -21,7 +21,7 @@ }, ) - const api = $derived(toast.group.connect(state, send, normalizeProps)) + const api = $derived(toast.group.connect(snapshot, send, normalizeProps)) let id: string | undefined = "" @@ -73,5 +73,5 @@ - + diff --git a/examples/svelte-ts/src/routes/toggle-group.svelte b/examples/svelte-ts/src/routes/toggle-group.svelte index ad8f226d4b..0d58f6fc0f 100644 --- a/examples/svelte-ts/src/routes/toggle-group.svelte +++ b/examples/svelte-ts/src/routes/toggle-group.svelte @@ -8,11 +8,11 @@ const controls = useControls(toggleGroupControls) - const [_state, send] = useMachine(toggle.machine({ id: "1" }), { + const [snapshot, send] = useMachine(toggle.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(toggle.connect(_state, send, normalizeProps)) + const api = $derived(toggle.connect(snapshot, send, normalizeProps)) @@ -27,5 +27,5 @@ - + diff --git a/examples/svelte-ts/src/routes/tooltip.svelte b/examples/svelte-ts/src/routes/tooltip.svelte index 49771ece97..1402169fdf 100644 --- a/examples/svelte-ts/src/routes/tooltip.svelte +++ b/examples/svelte-ts/src/routes/tooltip.svelte @@ -7,23 +7,23 @@ const id = "tip-1" const id2 = "tip-2" - const [_state, send] = useMachine(tooltip.machine({ id })) - const [_state2, send2] = useMachine(tooltip.machine({ id: id2 })) + const [snapshot, send] = useMachine(tooltip.machine({ id })) + const [snapshot2, send2] = useMachine(tooltip.machine({ id: id2 })) - const api = $derived(tooltip.connect(_state, send, normalizeProps)) - const api2 = $derived(tooltip.connect(_state2, send2, normalizeProps)) + const api = $derived(tooltip.connect(snapshot, send, normalizeProps)) + const api2 = $derived(tooltip.connect(snapshot2, send2, normalizeProps)) Hover me - {#if api.isOpen} + {#if api.open} Tooltip {/if} Over me - {#if api2.isOpen} + {#if api2.open} Tooltip 2 @@ -32,6 +32,6 @@ - - + + diff --git a/examples/svelte-ts/src/routes/tour.svelte b/examples/svelte-ts/src/routes/tour.svelte index 83a7e1ac6a..560698f068 100644 --- a/examples/svelte-ts/src/routes/tour.svelte +++ b/examples/svelte-ts/src/routes/tour.svelte @@ -7,11 +7,11 @@ const controls = useControls(tourControls) - const [state, send] = useMachine(tour.machine({ id: "1", steps: tourData }), { + const [snapshot, send] = useMachine(tour.machine({ id: "1", steps: tourData }), { context: controls.context, }) - const api = $derived(tour.connect(state, send, normalizeProps)) + const api = $derived(tour.connect(snapshot, send, normalizeProps)) @@ -20,9 +20,9 @@ Step 1 - + Step 2 - + Iframe Content @@ -37,13 +37,13 @@ - - + + {#if api.currentStep} - + {api.currentStep.title} {api.currentStep.description} diff --git a/examples/svelte-ts/src/routes/tree-view.svelte b/examples/svelte-ts/src/routes/tree-view.svelte index f3026b886a..5d8c97de7e 100644 --- a/examples/svelte-ts/src/routes/tree-view.svelte +++ b/examples/svelte-ts/src/routes/tree-view.svelte @@ -8,11 +8,11 @@ const controls = useControls(treeviewControls) - const [state, send] = useMachine(tree.machine({ id: "1" }), { + const [snapshot, send] = useMachine(tree.machine({ id: "1" }), { context: controls.context, }) - const api = $derived(tree.connect(state, send, normalizeProps)) + const api = $derived(tree.connect(snapshot, send, normalizeProps)) @@ -69,5 +69,5 @@ - + diff --git a/examples/vue-ts/package.json b/examples/vue-ts/package.json index 63811422f6..baef86a282 100644 --- a/examples/vue-ts/package.json +++ b/examples/vue-ts/package.json @@ -78,7 +78,6 @@ "@zag-js/tree-view": "workspace:*", "@zag-js/types": "workspace:*", "@zag-js/utils": "workspace:*", - "@zag-js/visually-hidden": "workspace:*", "@zag-js/vue": "workspace:*", "epic-spinners": "2.0.0", "form-serialize": "0.7.2", diff --git a/examples/vue-ts/src/pages/checkbox.tsx b/examples/vue-ts/src/pages/checkbox.tsx index f5b1af4eb6..f494d7d5f5 100644 --- a/examples/vue-ts/src/pages/checkbox.tsx +++ b/examples/vue-ts/src/pages/checkbox.tsx @@ -39,15 +39,15 @@ export default defineComponent({ - Input {api.isChecked ? "Checked" : "Unchecked"} + Input {api.checked ? "Checked" : "Unchecked"} Indicator - api.setChecked(true)}> + api.setChecked(true)}> Check - api.setChecked(false)}> + api.setChecked(false)}> Uncheck Reset Form diff --git a/examples/vue-ts/src/pages/clipboard.tsx b/examples/vue-ts/src/pages/clipboard.tsx index bd69e93881..452ec460fb 100644 --- a/examples/vue-ts/src/pages/clipboard.tsx +++ b/examples/vue-ts/src/pages/clipboard.tsx @@ -34,7 +34,7 @@ export default defineComponent({ Copy this link - {api.isCopied ? : } + {api.copied ? : } Copied! Copy diff --git a/examples/vue-ts/src/pages/collapsible.tsx b/examples/vue-ts/src/pages/collapsible.tsx index 8c4b204e92..5eda24b437 100644 --- a/examples/vue-ts/src/pages/collapsible.tsx +++ b/examples/vue-ts/src/pages/collapsible.tsx @@ -38,8 +38,8 @@ export default defineComponent({ Toggle Controls - Open - Close + api.setOpen(true)}>Open + api.setOpen(false)}>Close diff --git a/examples/vue-ts/src/pages/date-picker.tsx b/examples/vue-ts/src/pages/date-picker.tsx index 0c8ea2cd36..91c056739c 100644 --- a/examples/vue-ts/src/pages/date-picker.tsx +++ b/examples/vue-ts/src/pages/date-picker.tsx @@ -45,7 +45,7 @@ export default defineComponent({ - + ❌ 🗓 diff --git a/examples/vue-ts/src/pages/dialog.tsx b/examples/vue-ts/src/pages/dialog.tsx index d6310f7fd4..ea6e184f1d 100644 --- a/examples/vue-ts/src/pages/dialog.tsx +++ b/examples/vue-ts/src/pages/dialog.tsx @@ -30,7 +30,7 @@ export default defineComponent({ Open Dialog - {parentDialog.isOpen && ( + {parentDialog.open && ( @@ -47,7 +47,7 @@ export default defineComponent({ Open Nested - {childDialog.isOpen && ( + {childDialog.open && ( @@ -55,7 +55,7 @@ export default defineComponent({ X - parentDialog.close()} data-testid="special-close"> + parentDialog.setOpen(false)} data-testid="special-close"> Close Dialog 1 diff --git a/examples/vue-ts/src/pages/editable.tsx b/examples/vue-ts/src/pages/editable.tsx index 18c1fae366..37238315e2 100644 --- a/examples/vue-ts/src/pages/editable.tsx +++ b/examples/vue-ts/src/pages/editable.tsx @@ -29,12 +29,12 @@ export default defineComponent({ - {!api.isEditing && ( + {!api.editing && ( Edit )} - {api.isEditing && ( + {api.editing && ( <> Save diff --git a/examples/vue-ts/src/pages/hover-card.tsx b/examples/vue-ts/src/pages/hover-card.tsx index e7539bef97..9b6f4463e7 100644 --- a/examples/vue-ts/src/pages/hover-card.tsx +++ b/examples/vue-ts/src/pages/hover-card.tsx @@ -28,7 +28,7 @@ export default defineComponent({ Twitter - {api.isOpen && ( + {api.open && ( diff --git a/examples/vue-ts/src/pages/pagination.tsx b/examples/vue-ts/src/pages/pagination.tsx index 7540cc9caf..6c2f2a9bf9 100644 --- a/examples/vue-ts/src/pages/pagination.tsx +++ b/examples/vue-ts/src/pages/pagination.tsx @@ -1,6 +1,5 @@ import * as pagination from "@zag-js/pagination" import { normalizeProps, useMachine } from "@zag-js/vue" -import { visuallyHiddenStyle } from "@zag-js/visually-hidden" import { computed, defineComponent, h, Fragment } from "vue" import { paginationControls, paginationData } from "@zag-js/shared" import { StateVisualizer } from "../components/state-visualizer" @@ -60,9 +59,7 @@ export default defineComponent({ - - Previous Page - + Previous {api.pages.map((page, i) => { if (page.type === "page") @@ -81,9 +78,7 @@ export default defineComponent({ ) })} - - Next Page - + Next diff --git a/examples/vue-ts/src/pages/presence.tsx b/examples/vue-ts/src/pages/presence.tsx index 9d9ebab424..0c889bf9bb 100644 --- a/examples/vue-ts/src/pages/presence.tsx +++ b/examples/vue-ts/src/pages/presence.tsx @@ -26,7 +26,7 @@ export default defineComponent({ return ( (present.value = !present.value)}>Toggle - {api.isPresent && ( + {api.present && ( Content diff --git a/examples/vue-ts/src/pages/rating-group.tsx b/examples/vue-ts/src/pages/rating-group.tsx index b65dfecca6..5c4fbaff77 100644 --- a/examples/vue-ts/src/pages/rating-group.tsx +++ b/examples/vue-ts/src/pages/rating-group.tsx @@ -71,7 +71,7 @@ export default defineComponent({ const state = api.getItemState({ index }) return ( - {state.isHalf ? : } + {state.half ? : } ) })} diff --git a/examples/vue-ts/src/pages/switch.tsx b/examples/vue-ts/src/pages/switch.tsx index d9f7265bfb..2904483c8b 100644 --- a/examples/vue-ts/src/pages/switch.tsx +++ b/examples/vue-ts/src/pages/switch.tsx @@ -34,7 +34,7 @@ export default defineComponent({ - Feature is {api.isChecked ? "enabled" : "disabled"} + Feature is {api.checked ? "enabled" : "disabled"} diff --git a/examples/vue-ts/src/pages/toast.tsx b/examples/vue-ts/src/pages/toast.tsx index ccb081aeab..0460bcc005 100644 --- a/examples/vue-ts/src/pages/toast.tsx +++ b/examples/vue-ts/src/pages/toast.tsx @@ -19,26 +19,13 @@ const ToastItem = defineComponent({ setup(props) { const [state, send] = useActor(props.actor) const apiRef = computed(() => toast.connect(state.value, send, normalizeProps)) - const progressbarProps = computed(() => ({ - "data-scope": "toast", - "data-part": "progressbar", - "data-type": state.value.context.type, - style: { - opacity: apiRef.value.isVisible ? 1 : 0, - transformOrigin: apiRef.value.isRtl ? "right" : "left", - animationName: apiRef.value.type === "loading" ? "none" : undefined, - animationPlayState: apiRef.value.isPaused ? "paused" : "running", - animationDuration: "var(--duration)", - }, - })) - return () => { const api = apiRef.value return ( - + - + {api.type === "loading" && } {api.title} @@ -47,7 +34,7 @@ const ToastItem = defineComponent({ - + ) } }, diff --git a/examples/vue-ts/src/pages/tooltip.tsx b/examples/vue-ts/src/pages/tooltip.tsx index 824574adf3..a063f1ccc8 100644 --- a/examples/vue-ts/src/pages/tooltip.tsx +++ b/examples/vue-ts/src/pages/tooltip.tsx @@ -21,7 +21,7 @@ export default defineComponent({ Hover me - {api.isOpen && ( + {api.open && ( @@ -32,7 +32,7 @@ export default defineComponent({ )} Over me - {api2.isOpen && ( + {api2.open && ( diff --git a/packages/docs/data/api.json b/packages/docs/data/api.json index 2f23dd59b0..2365af393a 100644 --- a/packages/docs/data/api.json +++ b/packages/docs/data/api.json @@ -70,14 +70,10 @@ }, "avatar": { "api": { - "isLoaded": { + "loaded": { "type": "boolean", "description": "Whether the image is loaded." }, - "showFallback": { - "type": "boolean", - "description": "Whether the fallback is shown." - }, "setSrc": { "type": "(src: string) => void", "description": "Function to set new src." @@ -121,9 +117,9 @@ "type": "number", "description": "The current scroll progress of the carousel" }, - "isAutoplay": { + "autoPlaying": { "type": "boolean", - "description": "Whether the carousel is currently auto-playing" + "description": "Whether the carousel is auto playing" }, "canScrollNext": { "type": "boolean", @@ -209,19 +205,19 @@ }, "checkbox": { "api": { - "isChecked": { + "checked": { "type": "boolean", "description": "Whether the checkbox is checked" }, - "isDisabled": { + "disabled": { "type": "boolean", "description": "Whether the checkbox is disabled" }, - "isIndeterminate": { + "indeterminate": { "type": "boolean", "description": "Whether the checkbox is indeterminate" }, - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the checkbox is focused" }, @@ -245,27 +241,31 @@ }, "disabled": { "type": "boolean", - "description": "If `true`, the checkbox will be disabled" + "description": "Whether the checkbox is disabled" }, "invalid": { "type": "boolean", - "description": "If `true`, the checkbox is marked as invalid." + "description": "Whether the checkbox is invalid" }, "required": { "type": "boolean", - "description": "If `true`, the checkbox input is marked as required," + "description": "Whether the checkbox is required" }, "checked": { "type": "CheckedState", - "description": "If `true`, the checkbox will be checked." + "description": "The checked state of the checkbox" + }, + "readOnly": { + "type": "boolean", + "description": "Whether the checkbox is read-only" }, "onCheckedChange": { "type": "(details: CheckedChangeDetails) => void", - "description": "The callback invoked when the checked state of the `Checkbox` changes." + "description": "The callback invoked when the checked state changes." }, "name": { "type": "string", - "description": "The name of the input field in a checkbox. Useful for form submission." + "description": "The name of the input field in a checkbox.\nUseful for form submission." }, "form": { "type": "string", @@ -293,7 +293,7 @@ }, "clipboard": { "api": { - "isCopied": { + "copied": { "type": "boolean", "description": "Whether the value has been copied to the clipboard" }, @@ -339,25 +339,21 @@ }, "collapsible": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the collapsible is open." }, - "isVisible": { + "visible": { "type": "boolean", "description": "Whether the collapsible is visible (open or closing)" }, - "isDisabled": { + "disabled": { "type": "boolean", "description": "Whether the collapsible is disabled" }, - "open": { - "type": "() => void", - "description": "Function to open the collapsible." - }, - "close": { - "type": "() => void", - "description": "Function to close the collapsible." + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the collapsible." } }, "context": { @@ -402,11 +398,11 @@ }, "color-picker": { "api": { - "isDragging": { + "dragging": { "type": "boolean", "description": "Whether the color picker is being dragged" }, - "isOpen": { + "open": { "type": "boolean", "description": "Whether the color picker is open" }, @@ -446,13 +442,9 @@ "type": "(value: number) => void", "description": "Function to set the color alpha" }, - "open": { - "type": "() => void", - "description": "Function to open the color picker" - }, - "close": { - "type": "() => void", - "description": "Function to close the color picker" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the color picker" } }, "context": { @@ -544,15 +536,15 @@ }, "combobox": { "api": { - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the combobox is focused" }, - "isOpen": { + "open": { "type": "boolean", "description": "Whether the combobox is open" }, - "isInputValueEmpty": { + "inputEmpty": { "type": "boolean", "description": "Whether the combobox input value is empty" }, @@ -612,13 +604,9 @@ "type": "(props: ItemProps) => ItemState", "description": "Returns the state of a combobox item" }, - "open": { - "type": "() => void", - "description": "Function to open the combobox" - }, - "close": { - "type": "() => void", - "description": "Function to close the combobox" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the combobox" }, "collection": { "type": "Collection", @@ -795,11 +783,11 @@ }, "date-picker": { "api": { - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the input is focused" }, - "isOpen": { + "open": { "type": "boolean", "description": "Whether the date picker is open" }, @@ -883,13 +871,9 @@ "type": "() => void", "description": "Clears the selected date(s)." }, - "open": { - "type": "() => void", - "description": "Function to open the calendar." - }, - "close": { - "type": "() => void", - "description": "Function to close the calendar." + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the calendar." }, "focusMonth": { "type": "(month: number) => void", @@ -1076,17 +1060,13 @@ }, "dialog": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the dialog is open" }, - "open": { - "type": "() => void", - "description": "Function to open the dialog" - }, - "close": { - "type": "() => void", - "description": "Function to close the dialog" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the dialog" } }, "context": { @@ -1180,11 +1160,11 @@ }, "editable": { "api": { - "isEditing": { + "editing": { "type": "boolean", "description": "Whether the editable is in edit mode" }, - "isValueEmpty": { + "empty": { "type": "boolean", "description": "Whether the editable value is empty" }, @@ -1325,15 +1305,15 @@ }, "file-upload": { "api": { - "isDragging": { + "dragging": { "type": "boolean", "description": "Whether the user is dragging something over the root element" }, - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the user is focused on the dropzone element" }, - "open": { + "openFilePicker": { "type": "() => void", "description": "Function to open the file dialog" }, @@ -1449,15 +1429,19 @@ }, "floating-panel": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the panel is open" }, - "isDragging": { + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the panel" + }, + "dragging": { "type": "boolean", "description": "Whether the panel is being dragged" }, - "isResizing": { + "resizing": { "type": "boolean", "description": "Whether the panel is being resized" } @@ -1556,18 +1540,14 @@ }, "hover-card": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the hover card is open" }, - "open": { - "type": "() => void", + "setOpen": { + "type": "(open: boolean) => void", "description": "Function to open the hover card" }, - "close": { - "type": "() => void", - "description": "Function to close the hover card" - }, "reposition": { "type": "(options?: Partial) => void", "description": "Function to reposition the popover" @@ -1619,17 +1599,13 @@ }, "menu": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the menu is open" }, - "open": { - "type": "() => void", - "description": "Function to open the menu" - }, - "close": { - "type": "() => void", - "description": "Function to close the menu" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the menu" }, "highlightedValue": { "type": "string", @@ -1746,15 +1722,15 @@ }, "number-input": { "api": { - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the input is focused." }, - "isInvalid": { + "invalid": { "type": "boolean", "description": "Whether the input is invalid." }, - "isValueEmpty": { + "empty": { "type": "boolean", "description": "Whether the input value is empty." }, @@ -1939,14 +1915,6 @@ "type": "(data: V[]) => V[]", "description": "Function to slice an array of data based on the current page." }, - "isFirstPage": { - "type": "boolean", - "description": "Whether the current page is the first page." - }, - "isLastPage": { - "type": "boolean", - "description": "Whether the current page is the last page." - }, "setCount": { "type": "(count: number) => void", "description": "Function to set the total number of pages." @@ -2019,7 +1987,7 @@ "type": "string", "description": "The value of the input as a string." }, - "isValueComplete": { + "complete": { "type": "boolean", "description": "Whether all inputs are filled." }, @@ -2134,17 +2102,13 @@ "type": "boolean", "description": "Whether the popover is portalled" }, - "isOpen": { + "open": { "type": "boolean", "description": "Whether the popover is open" }, - "open": { - "type": "() => void", - "description": "Function to open the popover" - }, - "close": { - "type": "() => void", - "description": "Function to close the popover" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the popover" }, "reposition": { "type": "(options?: Partial) => void", @@ -2231,7 +2195,7 @@ }, "presence": { "api": { - "isPresent": { + "present": { "type": "boolean", "description": "Whether the node is present in the DOM." }, @@ -2351,6 +2315,10 @@ "type": "boolean", "description": "If `true`, the radio group will be disabled" }, + "readOnly": { + "type": "boolean", + "description": "Whether the checkbox is read-only" + }, "onValueChange": { "type": "(details: ValueChangeDetails) => void", "description": "Function called once a radio is checked" @@ -2384,7 +2352,7 @@ "type": "() => void", "description": "Clears the value of the rating group" }, - "isHovering": { + "hovering": { "type": "boolean", "description": "Whether the rating group is being hovered" }, @@ -2475,15 +2443,15 @@ }, "select": { "api": { - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the select is focused" }, - "isOpen": { + "open": { "type": "boolean", "description": "Whether the select is open" }, - "isValueEmpty": { + "empty": { "type": "boolean", "description": "Whether the select value is empty" }, @@ -2535,13 +2503,9 @@ "type": "(props: ItemProps) => ItemState", "description": "Returns the state of a select item" }, - "open": { - "type": "() => void", - "description": "Function to open the select" - }, - "close": { - "type": "() => void", - "description": "Function to close the select" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the select" }, "collection": { "type": "Collection", @@ -2662,11 +2626,11 @@ }, "signature-pad": { "api": { - "isEmpty": { + "empty": { "type": "boolean", "description": "Whether the signature pad is empty." }, - "isDrawing": { + "drawing": { "type": "boolean", "description": "Whether the user is currently drawing." }, @@ -2733,11 +2697,11 @@ "type": "number[]", "description": "The value of the slider." }, - "isDragging": { + "dragging": { "type": "boolean", "description": "Whether the slider is being dragged." }, - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the slider is focused." }, @@ -2840,7 +2804,7 @@ "description": "Function invoked when the slider's focused index changes" }, "getAriaValueText": { - "type": "(value: number, index: number) => string", + "type": "(details: ValueTextDetails) => string", "description": "Function that returns a human readable value for the slider thumb" }, "min": { @@ -2892,11 +2856,11 @@ }, "splitter": { "api": { - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the splitter is focused." }, - "isDragging": { + "dragging": { "type": "boolean", "description": "Whether the splitter is being dragged." }, @@ -2959,15 +2923,15 @@ }, "switch": { "api": { - "isChecked": { + "checked": { "type": "boolean", "description": "Whether the checkbox is checked" }, - "isDisabled": { + "disabled": { "type": "boolean", "description": "Whether the checkbox is disabled" }, - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the checkbox is focused" }, @@ -3001,6 +2965,10 @@ "type": "boolean", "description": "If `true`, the switch input is marked as required," }, + "readOnly": { + "type": "boolean", + "description": "Whether the switch is read-only" + }, "onCheckedChange": { "type": "(details: CheckedChangeDetails) => void", "description": "Function to call when the switch is clicked." @@ -3117,7 +3085,7 @@ }, "tags-input": { "api": { - "isEmpty": { + "empty": { "type": "boolean", "description": "Whether the tags are empty" }, @@ -3137,7 +3105,7 @@ "type": "number", "description": "The number of the tags." }, - "isAtMax": { + "atMax": { "type": "boolean", "description": "Whether the tags have reached the max limit." }, @@ -3357,18 +3325,14 @@ }, "tooltip": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the tooltip is open." }, - "open": { - "type": "() => void", + "setOpen": { + "type": "(open: boolean) => void", "description": "Function to open the tooltip." }, - "close": { - "type": "() => void", - "description": "Function to close the tooltip." - }, "reposition": { "type": "(options?: Partial) => void", "description": "Function to reposition the popover" diff --git a/packages/machines/accordion/src/accordion.connect.ts b/packages/machines/accordion/src/accordion.connect.ts index 0314780020..5e9b6219a3 100644 --- a/packages/machines/accordion/src/accordion.connect.ts +++ b/packages/machines/accordion/src/accordion.connect.ts @@ -20,9 +20,9 @@ export function connect(state: State, send: Send, normalize function getItemState(props: ItemProps): ItemState { return { - isOpen: value.includes(props.value), - isFocused: focusedValue === props.value, - isDisabled: Boolean(props.disabled ?? state.context.disabled), + expanded: value.includes(props.value), + focused: focusedValue === props.value, + disabled: Boolean(props.disabled ?? state.context.disabled), } } @@ -45,9 +45,9 @@ export function connect(state: State, send: Send, normalize ...parts.item.attrs, dir: state.context.dir, id: dom.getItemId(state.context, props.value), - "data-state": itemState.isOpen ? "open" : "closed", - "data-focus": dataAttr(itemState.isFocused), - "data-disabled": dataAttr(itemState.isDisabled), + "data-state": itemState.expanded ? "open" : "closed", + "data-focus": dataAttr(itemState.focused), + "data-disabled": dataAttr(itemState.disabled), "data-orientation": state.context.orientation, }) }, @@ -60,10 +60,10 @@ export function connect(state: State, send: Send, normalize role: "region", id: dom.getItemContentId(state.context, props.value), "aria-labelledby": dom.getItemTriggerId(state.context, props.value), - hidden: !itemState.isOpen, - "data-state": itemState.isOpen ? "open" : "closed", - "data-disabled": dataAttr(itemState.isDisabled), - "data-focus": dataAttr(itemState.isFocused), + hidden: !itemState.expanded, + "data-state": itemState.expanded ? "open" : "closed", + "data-disabled": dataAttr(itemState.disabled), + "data-focus": dataAttr(itemState.focused), "data-orientation": state.context.orientation, }) }, @@ -74,9 +74,9 @@ export function connect(state: State, send: Send, normalize ...parts.itemIndicator.attrs, dir: state.context.dir, "aria-hidden": true, - "data-state": itemState.isOpen ? "open" : "closed", - "data-disabled": dataAttr(itemState.isDisabled), - "data-focus": dataAttr(itemState.isFocused), + "data-state": itemState.expanded ? "open" : "closed", + "data-disabled": dataAttr(itemState.disabled), + "data-focus": dataAttr(itemState.focused), "data-orientation": state.context.orientation, }) }, @@ -91,22 +91,22 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, id: dom.getItemTriggerId(state.context, value), "aria-controls": dom.getItemContentId(state.context, value), - "aria-expanded": itemState.isOpen, - disabled: itemState.isDisabled, + "aria-expanded": itemState.expanded, + disabled: itemState.disabled, "data-orientation": state.context.orientation, - "aria-disabled": itemState.isDisabled, - "data-state": itemState.isOpen ? "open" : "closed", + "aria-disabled": itemState.disabled, + "data-state": itemState.expanded ? "open" : "closed", "data-ownedby": dom.getRootId(state.context), onFocus() { - if (itemState.isDisabled) return + if (itemState.disabled) return send({ type: "TRIGGER.FOCUS", value }) }, onBlur() { - if (itemState.isDisabled) return + if (itemState.disabled) return send("TRIGGER.BLUR") }, onClick(event) { - if (itemState.isDisabled) return + if (itemState.disabled) return if (isSafari()) { event.currentTarget.focus() } @@ -114,7 +114,7 @@ export function connect(state: State, send: Send, normalize }, onKeyDown(event) { if (event.defaultPrevented) return - if (itemState.isDisabled) return + if (itemState.disabled) return const keyMap: EventKeyMap = { ArrowDown() { diff --git a/packages/machines/accordion/src/accordion.types.ts b/packages/machines/accordion/src/accordion.types.ts index 93276bd2d1..7f98b6cfe5 100644 --- a/packages/machines/accordion/src/accordion.types.ts +++ b/packages/machines/accordion/src/accordion.types.ts @@ -50,11 +50,11 @@ interface PublicContext extends DirectionProperty, CommonProperties { /** * The callback fired when the state of opened/closed accordion items changes. */ - onValueChange?: (details: ValueChangeDetails) => void + onValueChange?(details: ValueChangeDetails): void /** * The callback fired when the focused accordion item changes. */ - onFocusChange?: (details: FocusChangeDetails) => void + onFocusChange?(details: FocusChangeDetails): void /** * The orientation of the accordion items. */ @@ -94,14 +94,29 @@ export type Send = S.Send * -----------------------------------------------------------------------------*/ export interface ItemProps { + /** + * The value of the accordion item. + */ value: string + /** + * Whether the accordion item is disabled. + */ disabled?: boolean } export interface ItemState { - isOpen: boolean - isFocused: boolean - isDisabled: boolean + /** + * Whether the accordion item is expanded. + */ + expanded: boolean + /** + * Whether the accordion item is focused. + */ + focused: boolean + /** + * Whether the accordion item is disabled. + */ + disabled: boolean } export interface MachineApi { @@ -120,7 +135,8 @@ export interface MachineApi { /** * Gets the state of an accordion item. */ - getItemState: (props: ItemProps) => ItemState + getItemState(props: ItemProps): ItemState + rootProps: T["element"] getItemProps(props: ItemProps): T["element"] getItemContentProps(props: ItemProps): T["element"] diff --git a/packages/machines/avatar/src/avatar.connect.ts b/packages/machines/avatar/src/avatar.connect.ts index 2b146a8686..9d8ec7535a 100644 --- a/packages/machines/avatar/src/avatar.connect.ts +++ b/packages/machines/avatar/src/avatar.connect.ts @@ -4,12 +4,9 @@ import { dom } from "./avatar.dom" import type { MachineApi, Send, State } from "./avatar.types" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { - const isLoaded = state.matches("loaded") - const showFallback = !isLoaded - + const loaded = state.matches("loaded") return { - isLoaded, - showFallback, + loaded, setSrc(src) { send({ type: "SRC.SET", src }) }, @@ -28,10 +25,10 @@ export function connect(state: State, send: Send, normalize imageProps: normalize.img({ ...parts.image.attrs, - hidden: !isLoaded, + hidden: !loaded, dir: state.context.dir, id: dom.getImageId(state.context), - "data-state": isLoaded ? "visible" : "hidden", + "data-state": loaded ? "visible" : "hidden", onLoad() { send({ type: "IMG.LOADED", src: "element" }) }, @@ -44,8 +41,8 @@ export function connect(state: State, send: Send, normalize ...parts.fallback.attrs, dir: state.context.dir, id: dom.getFallbackId(state.context), - hidden: isLoaded, - "data-state": isLoaded ? "hidden" : "visible", + hidden: loaded, + "data-state": loaded ? "hidden" : "visible", }), } } diff --git a/packages/machines/avatar/src/avatar.types.ts b/packages/machines/avatar/src/avatar.types.ts index 28ff0eef10..6421d361e1 100644 --- a/packages/machines/avatar/src/avatar.types.ts +++ b/packages/machines/avatar/src/avatar.types.ts @@ -5,8 +5,10 @@ import type { CommonProperties, DirectionProperty, PropTypes, RequiredBy } from * Callback details * -----------------------------------------------------------------------------*/ +export type LoadStatus = "error" | "loaded" + export interface StatusChangeDetails { - status: "loaded" | "error" + status: LoadStatus } /* ----------------------------------------------------------------------------- @@ -44,11 +46,7 @@ export interface MachineApi { /** * Whether the image is loaded. */ - isLoaded: boolean - /** - * Whether the fallback is shown. - */ - showFallback: boolean + loaded: boolean /** * Function to set new src. */ diff --git a/packages/machines/avatar/src/index.ts b/packages/machines/avatar/src/index.ts index 53c0204402..4ecd5fdbc8 100644 --- a/packages/machines/avatar/src/index.ts +++ b/packages/machines/avatar/src/index.ts @@ -2,4 +2,4 @@ export { anatomy } from "./avatar.anatomy" export { connect } from "./avatar.connect" export { machine } from "./avatar.machine" export * from "./avatar.props" -export type { MachineApi as Api, UserDefinedContext as Context, StatusChangeDetails } from "./avatar.types" +export type { MachineApi as Api, UserDefinedContext as Context, StatusChangeDetails, LoadStatus } from "./avatar.types" diff --git a/packages/machines/carousel/src/carousel.connect.ts b/packages/machines/carousel/src/carousel.connect.ts index b199e93c06..810902145b 100644 --- a/packages/machines/carousel/src/carousel.connect.ts +++ b/packages/machines/carousel/src/carousel.connect.ts @@ -2,14 +2,14 @@ import { dataAttr, isDom } from "@zag-js/dom-query" import type { NormalizeProps, PropTypes } from "@zag-js/types" import { parts } from "./carousel.anatomy" import { dom } from "./carousel.dom" -import type { MachineApi, Send, IndicatorProps, ItemProps, State, ItemState } from "./carousel.types" +import type { IndicatorProps, ItemProps, ItemState, MachineApi, Send, State } from "./carousel.types" import { getSlidesInView } from "./utils/get-slide-in-view" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { const canScrollNext = state.context.canScrollNext const canScrollPrev = state.context.canScrollPrev - const isHorizontal = state.context.isHorizontal - const isAutoplay = state.matches("autoplay") + const horizontal = state.context.isHorizontal + const autoPlaying = state.matches("autoplay") const activeSnap = state.context.scrollSnaps[state.context.index] const slidesInView = isDom() ? getSlidesInView(state.context)(activeSnap) : [] @@ -18,38 +18,32 @@ export function connect(state: State, send: Send, normalize const { index } = props return { valueText: `Slide ${index + 1}`, - isCurrent: index === state.context.index, - isNext: index === state.context.index + 1, - isPrevious: index === state.context.index - 1, - isInView: slidesInView.includes(index), + current: index === state.context.index, + next: index === state.context.index + 1, + previous: index === state.context.index - 1, + inView: slidesInView.includes(index), } } return { index: state.context.index, scrollProgress: state.context.scrollProgress, - isAutoplay, + autoPlaying, canScrollNext, canScrollPrev, - scrollTo(index, jump) { send({ type: "GOTO", index, jump }) }, - scrollToNext() { send("NEXT") }, - scrollToPrevious() { send("PREV") }, - getItemState: getItemState, - play() { send("PLAY") }, - pause() { send("PAUSE") }, @@ -82,8 +76,8 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, style: { display: "flex", - flexDirection: isHorizontal ? "row" : "column", - [isHorizontal ? "height" : "width"]: "auto", + flexDirection: horizontal ? "row" : "column", + [horizontal ? "height" : "width"]: "auto", gap: "var(--slide-spacing)", transform: state.context.translateValue, transitionProperty: "transform", @@ -101,8 +95,8 @@ export function connect(state: State, send: Send, normalize ...parts.item.attrs, id: dom.getItemId(state.context, index), dir: state.context.dir, - "data-current": dataAttr(sliderState.isCurrent), - "data-inview": dataAttr(sliderState.isInView), + "data-current": dataAttr(sliderState.current), + "data-inview": dataAttr(sliderState.inView), role: "group", "aria-roledescription": "slide", "data-orientation": state.context.orientation, @@ -110,7 +104,7 @@ export function connect(state: State, send: Send, normalize style: { position: "relative", flex: "0 0 var(--slide-size)", - [isHorizontal ? "minWidth" : "minHeight"]: "0px", + [horizontal ? "minWidth" : "minHeight"]: "0px", }, }) }, diff --git a/packages/machines/carousel/src/carousel.types.ts b/packages/machines/carousel/src/carousel.types.ts index b383c1bf8e..b92e9df1bd 100644 --- a/packages/machines/carousel/src/carousel.types.ts +++ b/packages/machines/carousel/src/carousel.types.ts @@ -98,15 +98,33 @@ export type Send = S.Send * -----------------------------------------------------------------------------*/ export interface ItemProps { + /** + * The index of the item. + */ index: number } export interface ItemState { + /** + * The text value of the item. Used for accessibility. + */ valueText: string - isCurrent: boolean - isNext: boolean - isPrevious: boolean - isInView: boolean + /** + * Whether the item is the current item in the carousel + */ + current: boolean + /** + * Whether the item is the next item in the carousel + */ + next: boolean + /** + * Whether the item is the previous item in the carousel + */ + previous: boolean + /** + * Whether the item is in view + */ + inView: boolean } export interface IndicatorProps { @@ -124,9 +142,9 @@ export interface MachineApi { */ scrollProgress: number /** - * Whether the carousel is currently auto-playing + * Whether the carousel is auto playing */ - isAutoplay: boolean + autoPlaying: boolean /** * Whether the carousel is can scroll to the next slide */ diff --git a/packages/machines/checkbox/package.json b/packages/machines/checkbox/package.json index e1a9a13721..e7f490b20e 100644 --- a/packages/machines/checkbox/package.json +++ b/packages/machines/checkbox/package.json @@ -41,7 +41,6 @@ "@zag-js/types": "workspace:*", "@zag-js/dom-query": "workspace:*", "@zag-js/dom-event": "workspace:*", - "@zag-js/visually-hidden": "workspace:*", "@zag-js/form-utils": "workspace:*", "@zag-js/utils": "workspace:*" }, diff --git a/packages/machines/checkbox/src/checkbox.connect.ts b/packages/machines/checkbox/src/checkbox.connect.ts index 307448656d..ff16d983b3 100644 --- a/packages/machines/checkbox/src/checkbox.connect.ts +++ b/packages/machines/checkbox/src/checkbox.connect.ts @@ -1,38 +1,39 @@ -import { dataAttr } from "@zag-js/dom-query" +import { dataAttr, visuallyHiddenStyle } from "@zag-js/dom-query" import type { NormalizeProps, PropTypes } from "@zag-js/types" -import { visuallyHiddenStyle } from "@zag-js/visually-hidden" import { parts } from "./checkbox.anatomy" import { dom } from "./checkbox.dom" -import type { CheckedState, MachineApi, Send, State } from "./checkbox.types" +import type { MachineApi, Send, State } from "./checkbox.types" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { - const isDisabled = state.context.isDisabled - const isFocused = !isDisabled && state.context.focused - const isChecked = state.context.isChecked - const isIndeterminate = state.context.isIndeterminate + const disabled = state.context.isDisabled + const focused = !disabled && state.context.focused + const checked = state.context.isChecked + const indeterminate = state.context.isIndeterminate + const readOnly = state.context.readOnly const dataAttrs = { "data-active": dataAttr(state.context.active), - "data-focus": dataAttr(isFocused), + "data-focus": dataAttr(focused), + "data-readonly": dataAttr(readOnly), "data-hover": dataAttr(state.context.hovered), - "data-disabled": dataAttr(isDisabled), - "data-state": isIndeterminate ? "indeterminate" : state.context.checked ? "checked" : "unchecked", + "data-disabled": dataAttr(disabled), + "data-state": indeterminate ? "indeterminate" : state.context.checked ? "checked" : "unchecked", "data-invalid": dataAttr(state.context.invalid), } return { - isChecked, - isDisabled, - isIndeterminate, - isFocused, + checked, + disabled, + indeterminate, + focused, checkedState: state.context.checked, - setChecked(checked: CheckedState) { + setChecked(checked) { send({ type: "CHECKED.SET", checked, isTrusted: false }) }, toggleChecked() { - send({ type: "CHECKED.TOGGLE", checked: isChecked, isTrusted: false }) + send({ type: "CHECKED.TOGGLE", checked: checked, isTrusted: false }) }, rootProps: normalize.label({ @@ -42,11 +43,11 @@ export function connect(state: State, send: Send, normalize id: dom.getRootId(state.context), htmlFor: dom.getHiddenInputId(state.context), onPointerMove() { - if (isDisabled) return + if (disabled) return send({ type: "CONTEXT.SET", context: { hovered: true } }) }, onPointerLeave() { - if (isDisabled) return + if (disabled) return send({ type: "CONTEXT.SET", context: { hovered: false } }) }, onClick(event) { @@ -75,16 +76,16 @@ export function connect(state: State, send: Send, normalize ...parts.indicator.attrs, ...dataAttrs, dir: state.context.dir, - hidden: !isIndeterminate && !state.context.checked, + hidden: !indeterminate && !state.context.checked, }), hiddenInputProps: normalize.input({ id: dom.getHiddenInputId(state.context), type: "checkbox", required: state.context.required, - defaultChecked: isChecked, - disabled: isDisabled, - "data-disabled": dataAttr(isDisabled), + defaultChecked: checked, + disabled: disabled, + "data-disabled": dataAttr(disabled), "aria-labelledby": dom.getLabelId(state.context), "aria-invalid": state.context.invalid, name: state.context.name, @@ -92,6 +93,11 @@ export function connect(state: State, send: Send, normalize value: state.context.value, style: visuallyHiddenStyle, onChange(event) { + if (readOnly) { + event.preventDefault() + return + } + const checked = event.currentTarget.checked send({ type: "CHECKED.SET", checked, isTrusted: true }) }, diff --git a/packages/machines/checkbox/src/checkbox.props.ts b/packages/machines/checkbox/src/checkbox.props.ts index f0072b357b..46e1903a4f 100644 --- a/packages/machines/checkbox/src/checkbox.props.ts +++ b/packages/machines/checkbox/src/checkbox.props.ts @@ -13,6 +13,7 @@ export const props = createProps()([ "invalid", "name", "onCheckedChange", + "readOnly", "required", "value", ]) diff --git a/packages/machines/checkbox/src/checkbox.types.ts b/packages/machines/checkbox/src/checkbox.types.ts index b41e80e46f..d3be097554 100644 --- a/packages/machines/checkbox/src/checkbox.types.ts +++ b/packages/machines/checkbox/src/checkbox.types.ts @@ -28,27 +28,32 @@ interface PublicContext extends DirectionProperty, CommonProperties { */ ids?: ElementIds /** - * If `true`, the checkbox will be disabled + * Whether the checkbox is disabled */ disabled?: boolean /** - * If `true`, the checkbox is marked as invalid. + * Whether the checkbox is invalid */ invalid?: boolean /** - * If `true`, the checkbox input is marked as required, + * Whether the checkbox is required */ required?: boolean /** - * If `true`, the checkbox will be checked. + * The checked state of the checkbox */ checked: CheckedState /** - * The callback invoked when the checked state of the `Checkbox` changes. + * Whether the checkbox is read-only + */ + readOnly?: boolean + /** + * The callback invoked when the checked state changes. */ onCheckedChange?(details: CheckedChangeDetails): void /** - * The name of the input field in a checkbox. Useful for form submission. + * The name of the input field in a checkbox. + * Useful for form submission. */ name?: string /** @@ -120,19 +125,19 @@ export interface MachineApi { /** * Whether the checkbox is checked */ - isChecked: boolean + checked: boolean /** * Whether the checkbox is disabled */ - isDisabled: boolean | undefined + disabled: boolean | undefined /** * Whether the checkbox is indeterminate */ - isIndeterminate: boolean + indeterminate: boolean /** * Whether the checkbox is focused */ - isFocused: boolean | undefined + focused: boolean | undefined /** * The checked state of the checkbox */ diff --git a/packages/machines/clipboard/src/clipboard.connect.ts b/packages/machines/clipboard/src/clipboard.connect.ts index ed630cec6e..db267e5c61 100644 --- a/packages/machines/clipboard/src/clipboard.connect.ts +++ b/packages/machines/clipboard/src/clipboard.connect.ts @@ -5,10 +5,10 @@ import type { MachineApi, Send, State } from "./clipboard.types" import { dom } from "./clipboard.dom" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { - const isCopied = state.matches("copied") + const copied = state.matches("copied") return { - isCopied, + copied, value: state.context.value, setValue(value) { send({ type: "VALUE.SET", value }) @@ -18,23 +18,23 @@ export function connect(state: State, send: Send, normalize }, rootProps: normalize.element({ ...parts.root.attrs, - "data-copied": dataAttr(isCopied), + "data-copied": dataAttr(copied), id: dom.getRootId(state.context), }), labelProps: normalize.label({ ...parts.label.attrs, htmlFor: dom.getInputId(state.context), - "data-copied": dataAttr(isCopied), + "data-copied": dataAttr(copied), id: dom.getLabelId(state.context), }), controlProps: normalize.element({ ...parts.control.attrs, - "data-copied": dataAttr(isCopied), + "data-copied": dataAttr(copied), }), inputProps: normalize.input({ ...parts.input.attrs, defaultValue: state.context.value, - "data-copied": dataAttr(isCopied), + "data-copied": dataAttr(copied), readOnly: true, "data-readonly": "true", id: dom.getInputId(state.context), @@ -47,8 +47,8 @@ export function connect(state: State, send: Send, normalize }), triggerProps: normalize.button({ ...parts.trigger.attrs, - "aria-label": isCopied ? "Copied to clipboard" : "Copy to clipboard", - "data-copied": dataAttr(isCopied), + "aria-label": copied ? "Copied to clipboard" : "Copy to clipboard", + "data-copied": dataAttr(copied), onClick() { send({ type: "COPY" }) }, @@ -56,7 +56,7 @@ export function connect(state: State, send: Send, normalize getIndicatorProps(props) { return normalize.element({ ...parts.indicator.attrs, - hidden: props.copied !== isCopied, + hidden: props.copied !== copied, }) }, } diff --git a/packages/machines/clipboard/src/clipboard.types.ts b/packages/machines/clipboard/src/clipboard.types.ts index 89fb00c7c0..ad5c700061 100644 --- a/packages/machines/clipboard/src/clipboard.types.ts +++ b/packages/machines/clipboard/src/clipboard.types.ts @@ -58,7 +58,7 @@ export interface MachineApi { /** * Whether the value has been copied to the clipboard */ - isCopied: boolean + copied: boolean /** * The value to be copied to the clipboard */ diff --git a/packages/machines/collapsible/src/collapsible.connect.ts b/packages/machines/collapsible/src/collapsible.connect.ts index 7d2fcfd25d..7034c3daf5 100644 --- a/packages/machines/collapsible/src/collapsible.connect.ts +++ b/packages/machines/collapsible/src/collapsible.connect.ts @@ -5,39 +5,37 @@ import { dom } from "./collapsible.dom" import type { MachineApi, Send, State } from "./collapsible.types" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { - const isVisible = state.matches("open", "closing") - const isOpen = state.matches("open") + const visible = state.matches("open", "closing") + const open = state.matches("open") const height = state.context.height const width = state.context.width - const isDisabled = !!state.context.disabled + const disabled = !!state.context.disabled - const skipMountAnimation = state.context.isMountAnimationPrevented && isOpen + const skipMountAnimation = state.context.isMountAnimationPrevented && open return { - isDisabled, - isVisible, - isOpen, - open() { - send("OPEN") - }, - close() { - send("CLOSE") + disabled, + visible, + open, + setOpen(_open) { + if (_open === open) return + send(_open ? "OPEN" : "CLOSE") }, rootProps: normalize.element({ ...parts.root.attrs, - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", dir: state.context.dir, id: dom.getRootId(state.context), }), contentProps: normalize.element({ ...parts.content.attrs, - "data-state": skipMountAnimation ? undefined : isOpen ? "open" : "closed", + "data-state": skipMountAnimation ? undefined : open ? "open" : "closed", id: dom.getContentId(state.context), - "data-disabled": dataAttr(isDisabled), - hidden: !isVisible, + "data-disabled": dataAttr(disabled), + hidden: !visible, style: { "--height": height != null ? `${height}px` : undefined, "--width": width != null ? `${width}px` : undefined, @@ -49,13 +47,13 @@ export function connect(state: State, send: Send, normalize id: dom.getTriggerId(state.context), dir: state.context.dir, type: "button", - "data-state": isOpen ? "open" : "closed", - "data-disabled": dataAttr(isDisabled), + "data-state": open ? "open" : "closed", + "data-disabled": dataAttr(disabled), "aria-controls": dom.getContentId(state.context), - "aria-expanded": isVisible || false, + "aria-expanded": visible || false, onClick() { - if (isDisabled) return - send({ type: isOpen ? "CLOSE" : "OPEN", src: "trigger.click" }) + if (disabled) return + send({ type: open ? "CLOSE" : "OPEN", src: "trigger.click" }) }, }), } diff --git a/packages/machines/collapsible/src/collapsible.types.ts b/packages/machines/collapsible/src/collapsible.types.ts index 1534bcd502..a203963455 100644 --- a/packages/machines/collapsible/src/collapsible.types.ts +++ b/packages/machines/collapsible/src/collapsible.types.ts @@ -91,23 +91,20 @@ export interface MachineApi { /** * Whether the collapsible is open. */ - isOpen: boolean + open: boolean /** * Whether the collapsible is visible (open or closing) */ - isVisible: boolean + visible: boolean /** * Whether the collapsible is disabled */ - isDisabled: boolean - /** - * Function to open the collapsible. - */ - open(): void + disabled: boolean /** - * Function to close the collapsible. + * Function to open or close the collapsible. */ - close(): void + setOpen(open: boolean): void + rootProps: T["element"] triggerProps: T["button"] contentProps: T["element"] diff --git a/packages/machines/color-picker/package.json b/packages/machines/color-picker/package.json index d7a2811237..8905765bcc 100644 --- a/packages/machines/color-picker/package.json +++ b/packages/machines/color-picker/package.json @@ -44,7 +44,6 @@ "@zag-js/utils": "workspace:*", "@zag-js/form-utils": "workspace:*", "@zag-js/color-utils": "workspace:*", - "@zag-js/visually-hidden": "workspace:*", "@zag-js/popper": "workspace:*", "@zag-js/text-selection": "workspace:*", "@zag-js/types": "workspace:*" diff --git a/packages/machines/color-picker/src/color-picker.connect.ts b/packages/machines/color-picker/src/color-picker.connect.ts index f284442c8b..ad4988e790 100644 --- a/packages/machines/color-picker/src/color-picker.connect.ts +++ b/packages/machines/color-picker/src/color-picker.connect.ts @@ -8,10 +8,9 @@ import { isModifierKey, type EventKeyMap, } from "@zag-js/dom-event" -import { dataAttr, query } from "@zag-js/dom-query" +import { dataAttr, query, visuallyHiddenStyle } from "@zag-js/dom-query" import { getPlacementStyles } from "@zag-js/popper" import type { NormalizeProps, PropTypes } from "@zag-js/types" -import { visuallyHiddenStyle } from "@zag-js/visually-hidden" import { parts } from "./color-picker.anatomy" import { dom } from "./color-picker.dom" import type { @@ -32,12 +31,12 @@ export function connect(state: State, send: Send, normalize const areaValue = state.context.areaValue const valueAsString = state.context.valueAsString - const isDisabled = state.context.isDisabled - const isInteractive = state.context.isInteractive + const disabled = state.context.isDisabled + const interactive = state.context.isInteractive - const isDragging = state.hasTag("dragging") - const isOpen = state.hasTag("open") - const isFocused = state.hasTag("focused") + const dragging = state.hasTag("dragging") + const open = state.hasTag("open") + const focused = state.hasTag("focused") const getAreaChannels = (props: AreaProps) => { const channels = areaValue.getChannels() @@ -58,21 +57,19 @@ export function connect(state: State, send: Send, normalize return { value: color, valueAsString: color.toString("hex"), - isChecked: color.isEqual(value), - isDisabled: props.disabled || !isInteractive, + checked: color.isEqual(value), + disabled: props.disabled || !interactive, } } return { - isDragging, - isOpen, + dragging, + open, valueAsString, value, - open() { - send({ type: "OPEN" }) - }, - close() { - send({ type: "CLOSE" }) + setOpen(_open) { + if (_open === open) return + send({ type: _open ? "OPEN" : "CLOSE" }) }, setValue(value) { send({ type: "VALUE.SET", value: normalizeColor(value), src: "set-color" }) @@ -99,7 +96,7 @@ export function connect(state: State, send: Send, normalize ...parts.root.attrs, dir: state.context.dir, id: dom.getRootId(state.context), - "data-disabled": dataAttr(isDisabled), + "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(state.context.readOnly), style: { "--value": value.toString("css"), @@ -111,9 +108,9 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, id: dom.getLabelId(state.context), htmlFor: dom.getHiddenInputId(state.context), - "data-disabled": dataAttr(isDisabled), + "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(state.context.readOnly), - "data-focus": dataAttr(isFocused), + "data-focus": dataAttr(focused), onClick(event) { event.preventDefault() const inputEl = query(dom.getControlEl(state.context), "[data-channel=hex]") @@ -125,33 +122,33 @@ export function connect(state: State, send: Send, normalize ...parts.control.attrs, id: dom.getControlId(state.context), dir: state.context.dir, - "data-disabled": dataAttr(isDisabled), + "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(state.context.readOnly), - "data-state": isOpen ? "open" : "closed", - "data-focus": dataAttr(isFocused), + "data-state": open ? "open" : "closed", + "data-focus": dataAttr(focused), }), triggerProps: normalize.button({ ...parts.trigger.attrs, id: dom.getTriggerId(state.context), dir: state.context.dir, - disabled: isDisabled, + disabled: disabled, "aria-label": `select color. current color is ${valueAsString}`, "aria-controls": dom.getContentId(state.context), "aria-labelledby": dom.getLabelId(state.context), - "data-disabled": dataAttr(isDisabled), + "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(state.context.readOnly), "data-placement": currentPlacement, - "aria-expanded": dataAttr(isOpen), - "data-state": isOpen ? "open" : "closed", - "data-focus": dataAttr(isFocused), + "aria-expanded": dataAttr(open), + "data-state": open ? "open" : "closed", + "data-focus": dataAttr(focused), type: "button", onClick() { - if (!isInteractive) return + if (!interactive) return send({ type: "TRIGGER.CLICK" }) }, onBlur() { - if (!isInteractive) return + if (!interactive) return send({ type: "TRIGGER.BLUR" }) }, style: { @@ -171,8 +168,8 @@ export function connect(state: State, send: Send, normalize id: dom.getContentId(state.context), dir: state.context.dir, "data-placement": currentPlacement, - "data-state": isOpen ? "open" : "closed", - hidden: !isOpen, + "data-state": open ? "open" : "closed", + hidden: !open, }), getAreaProps(props = {}) { @@ -188,7 +185,7 @@ export function connect(state: State, send: Send, normalize id: dom.getAreaId(state.context), role: "group", onPointerDown(event) { - if (!isInteractive) return + if (!interactive) return const evt = getNativeEvent(event) if (!isLeftClick(evt) || isModifierKey(evt)) return @@ -242,8 +239,8 @@ export function connect(state: State, send: Send, normalize ...parts.areaThumb.attrs, id: dom.getAreaThumbId(state.context), dir: state.context.dir, - tabIndex: isDisabled ? undefined : 0, - "data-disabled": dataAttr(isDisabled), + tabIndex: disabled ? undefined : 0, + "data-disabled": dataAttr(disabled), role: "slider", "aria-valuemin": 0, "aria-valuemax": 100, @@ -261,12 +258,12 @@ export function connect(state: State, send: Send, normalize background: areaValue.withChannelValue("alpha", 1).toString("css"), }, onFocus() { - if (!isInteractive) return + if (!interactive) return send({ type: "AREA.FOCUS", id: "area", channel }) }, onKeyDown(event) { if (event.defaultPrevented) return - if (!isInteractive) return + if (!interactive) return const step = getEventStep(event) @@ -331,7 +328,7 @@ export function connect(state: State, send: Send, normalize "data-orientation": orientation, role: "presentation", onPointerDown(event) { - if (!isInteractive) return + if (!interactive) return const evt = getNativeEvent(event) if (!isLeftClick(evt) || isModifierKey(evt)) return @@ -387,11 +384,11 @@ export function connect(state: State, send: Send, normalize id: dom.getChannelSliderThumbId(state.context, channel), role: "slider", "aria-label": channel, - tabIndex: isDisabled ? undefined : 0, + tabIndex: disabled ? undefined : 0, "data-channel": channel, - "data-disabled": dataAttr(isDisabled), + "data-disabled": dataAttr(disabled), "data-orientation": orientation, - "aria-disabled": dataAttr(isDisabled), + "aria-disabled": dataAttr(disabled), "aria-orientation": orientation, "aria-valuemax": maxValue, "aria-valuemin": minValue, @@ -404,12 +401,12 @@ export function connect(state: State, send: Send, normalize ...placementStyles, }, onFocus() { - if (!isInteractive) return + if (!interactive) return send({ type: "CHANNEL_SLIDER.FOCUS", channel }) }, onKeyDown(event) { if (event.defaultPrevented) return - if (!isInteractive) return + if (!interactive) return const step = getEventStep(event) * stepValue @@ -466,33 +463,33 @@ export function connect(state: State, send: Send, normalize "aria-label": channel, spellCheck: false, autoComplete: "off", - disabled: isDisabled, - "data-disabled": dataAttr(isDisabled), + disabled: disabled, + "data-disabled": dataAttr(disabled), readOnly: state.context.readOnly, defaultValue: getChannelValue(value, channel), min: range?.minValue, max: range?.maxValue, step: range?.step, onBeforeInput(event) { - if (isTextField || !isInteractive) return + if (isTextField || !interactive) return const value = event.currentTarget.value if (value.match(/[^0-9.]/g)) { event.preventDefault() } }, onFocus(event) { - if (!isInteractive) return + if (!interactive) return send({ type: "CHANNEL_INPUT.FOCUS", channel }) event.target.select() }, onBlur(event) { - if (!isInteractive) return + if (!interactive) return const value = isTextField ? event.currentTarget.value : event.currentTarget.valueAsNumber send({ type: "CHANNEL_INPUT.BLUR", channel, value, isTextField }) }, onKeyDown(event) { if (event.defaultPrevented) return - if (!isInteractive) return + if (!interactive) return if (event.key === "Enter") { const value = isTextField ? event.currentTarget.value : event.currentTarget.valueAsNumber send({ type: "CHANNEL_INPUT.CHANGE", channel, value, isTextField }) @@ -509,7 +506,7 @@ export function connect(state: State, send: Send, normalize hiddenInputProps: normalize.input({ type: "text", - disabled: isDisabled, + disabled: disabled, name: state.context.name, id: dom.getHiddenInputId(state.context), style: visuallyHiddenStyle, @@ -520,11 +517,11 @@ export function connect(state: State, send: Send, normalize ...parts.eyeDropperTrigger.attrs, type: "button", dir: state.context.dir, - disabled: isDisabled, - "data-disabled": dataAttr(isDisabled), + disabled: disabled, + "data-disabled": dataAttr(disabled), "aria-label": "Pick a color from the screen", onClick() { - if (!isInteractive) return + if (!interactive) return send("EYEDROPPER.CLICK") }, }), @@ -540,15 +537,15 @@ export function connect(state: State, send: Send, normalize const triggerState = getSwatchTriggerState(props) return normalize.button({ ...parts.swatchTrigger.attrs, - disabled: triggerState.isDisabled, + disabled: triggerState.disabled, dir: state.context.dir, type: "button", "aria-label": `select ${triggerState.valueAsString} as the color`, - "data-state": triggerState.isChecked ? "checked" : "unchecked", + "data-state": triggerState.checked ? "checked" : "unchecked", "data-value": triggerState.valueAsString, - "data-disabled": dataAttr(triggerState.isDisabled), + "data-disabled": dataAttr(triggerState.disabled), onClick() { - if (triggerState.isDisabled) return + if (triggerState.disabled) return send({ type: "SWATCH_TRIGGER.CLICK", value: triggerState.value }) }, style: { @@ -562,7 +559,7 @@ export function connect(state: State, send: Send, normalize return normalize.element({ ...parts.swatchIndicator.attrs, dir: state.context.dir, - hidden: !triggerState.isChecked, + hidden: !triggerState.checked, }) }, @@ -572,7 +569,7 @@ export function connect(state: State, send: Send, normalize return normalize.element({ ...parts.swatch.attrs, dir: state.context.dir, - "data-state": triggerState.isChecked ? "checked" : "unchecked", + "data-state": triggerState.checked ? "checked" : "unchecked", "data-value": triggerState.valueAsString, style: { position: "relative", @@ -598,7 +595,7 @@ export function connect(state: State, send: Send, normalize "aria-label": "change color format", dir: state.context.dir, defaultValue: state.context.format, - disabled: isDisabled, + disabled: disabled, onChange(event) { const format = assertFormat(event.currentTarget.value) send({ type: "FORMAT.SET", format, src: "format-select" }) diff --git a/packages/machines/color-picker/src/color-picker.machine.ts b/packages/machines/color-picker/src/color-picker.machine.ts index b0a1d271fa..4bb0f1a20f 100644 --- a/packages/machines/color-picker/src/color-picker.machine.ts +++ b/packages/machines/color-picker/src/color-picker.machine.ts @@ -404,11 +404,11 @@ export function machine(userContext: UserDefinedContext) { openEyeDropper(ctx) { const isSupported = "EyeDropper" in dom.getWin(ctx) if (!isSupported) return - const win = dom.getWin(ctx) as any + const win = dom.getWin(ctx) const picker = new win.EyeDropper() picker .open() - .then(({ sRGBHex }: { sRGBHex: string }) => { + .then(({ sRGBHex }) => { const format = ctx.value.getFormat() const color = parseColor(sRGBHex).toFormat(format) as Color set.value(ctx, color) diff --git a/packages/machines/color-picker/src/color-picker.types.ts b/packages/machines/color-picker/src/color-picker.types.ts index d01e222427..c6dd65a700 100644 --- a/packages/machines/color-picker/src/color-picker.types.ts +++ b/packages/machines/color-picker/src/color-picker.types.ts @@ -7,6 +7,20 @@ import type { MaybeFunction } from "@zag-js/utils" export type ExtendedColorChannel = ColorChannel | "hex" | "css" +// patch the global window object to include the EyeDropper API + +interface EyeDropper { + new (): EyeDropper + open: (options?: { signal?: AbortSignal }) => Promise<{ sRGBHex: string }> + [Symbol.toStringTag]: "EyeDropper" +} + +declare global { + interface Window { + EyeDropper: EyeDropper + } +} + /* ----------------------------------------------------------------------------- * Callback details * -----------------------------------------------------------------------------*/ @@ -218,8 +232,8 @@ export interface SwatchTriggerProps { export interface SwatchTriggerState { value: Color valueAsString: string - isChecked: boolean - isDisabled: boolean + checked: boolean + disabled: boolean } export interface SwatchProps { @@ -241,11 +255,11 @@ export interface MachineApi { /** * Whether the color picker is being dragged */ - isDragging: boolean + dragging: boolean /** * Whether the color picker is open */ - isOpen: boolean + open: boolean /** * The current color value (as a string) */ @@ -283,13 +297,9 @@ export interface MachineApi { */ setAlpha(value: number): void /** - * Function to open the color picker - */ - open(): void - /** - * Function to close the color picker + * Function to open or close the color picker */ - close(): void + setOpen(open: boolean): void rootProps: T["element"] labelProps: T["element"] diff --git a/packages/machines/combobox/src/combobox.connect.ts b/packages/machines/combobox/src/combobox.connect.ts index c698c343e7..56bea6054a 100644 --- a/packages/machines/combobox/src/combobox.connect.ts +++ b/packages/machines/combobox/src/combobox.connect.ts @@ -11,7 +11,7 @@ import { getPlacementStyles } from "@zag-js/popper" import type { NormalizeProps, PropTypes } from "@zag-js/types" import { parts } from "./combobox.anatomy" import { dom } from "./combobox.dom" -import type { CollectionItem, ItemProps, MachineApi, Send, State } from "./combobox.types" +import type { CollectionItem, ItemProps, ItemState, MachineApi, Send, State } from "./combobox.types" export function connect( state: State, @@ -21,13 +21,13 @@ export function connect( const translations = state.context.translations const collection = state.context.collection - const isDisabled = state.context.disabled - const isInteractive = state.context.isInteractive - const isInvalid = state.context.invalid - const isReadOnly = state.context.readOnly + const disabled = state.context.disabled + const interactive = state.context.isInteractive + const invalid = state.context.invalid + const readOnly = state.context.readOnly - const isOpen = state.hasTag("open") - const isFocused = state.hasTag("focused") + const open = state.hasTag("open") + const focused = state.hasTag("focused") const isDialogPopup = state.context.popup === "dialog" const popperStyles = getPlacementStyles({ @@ -35,23 +35,23 @@ export function connect( placement: state.context.currentPlacement, }) - function getItemState(props: ItemProps) { + function getItemState(props: ItemProps): ItemState { const { item } = props const disabled = collection.isItemDisabled(item) const value = collection.itemToValue(item) return { value, - isDisabled: Boolean(disabled || isDisabled), - isHighlighted: state.context.highlightedValue === value, - isSelected: state.context.value.includes(value), + disabled: Boolean(disabled || disabled), + highlighted: state.context.highlightedValue === value, + selected: state.context.value.includes(value), } } return { - isFocused, - isOpen, + focused, + open, inputValue: state.context.inputValue, - isInputValueEmpty: state.context.isInputValueEmpty, + inputEmpty: state.context.isInputValueEmpty, highlightedValue: state.context.highlightedValue, highlightedItem: state.context.highlightedItem, value: state.context.value, @@ -87,21 +87,16 @@ export function connect( focus() { dom.getInputEl(state.context)?.focus() }, - open() { - if (isOpen) return - send("OPEN") + setOpen(_open) { + if (_open === open) return + send(_open ? "OPEN" : "CLOSE") }, - close() { - if (!isOpen) return - send("CLOSE") - }, - rootProps: normalize.element({ ...parts.root.attrs, dir: state.context.dir, id: dom.getRootId(state.context), - "data-invalid": dataAttr(isInvalid), - "data-readonly": dataAttr(isReadOnly), + "data-invalid": dataAttr(invalid), + "data-readonly": dataAttr(readOnly), }), labelProps: normalize.label({ @@ -109,10 +104,10 @@ export function connect( dir: state.context.dir, htmlFor: dom.getInputId(state.context), id: dom.getLabelId(state.context), - "data-readonly": dataAttr(isReadOnly), - "data-disabled": dataAttr(isDisabled), - "data-invalid": dataAttr(isInvalid), - "data-focus": dataAttr(isFocused), + "data-readonly": dataAttr(readOnly), + "data-disabled": dataAttr(disabled), + "data-invalid": dataAttr(invalid), + "data-focus": dataAttr(focused), onClick(event) { if (!isDialogPopup) return event.preventDefault() @@ -124,10 +119,10 @@ export function connect( ...parts.control.attrs, dir: state.context.dir, id: dom.getControlId(state.context), - "data-state": isOpen ? "open" : "closed", - "data-focus": dataAttr(isFocused), - "data-disabled": dataAttr(isDisabled), - "data-invalid": dataAttr(isInvalid), + "data-state": open ? "open" : "closed", + "data-focus": dataAttr(focused), + "data-disabled": dataAttr(disabled), + "data-invalid": dataAttr(invalid), }), positionerProps: normalize.element({ @@ -140,17 +135,17 @@ export function connect( inputProps: normalize.input({ ...parts.input.attrs, dir: state.context.dir, - "aria-invalid": ariaAttr(isInvalid), - "data-invalid": dataAttr(isInvalid), + "aria-invalid": ariaAttr(invalid), + "data-invalid": dataAttr(invalid), name: state.context.name, form: state.context.form, - disabled: isDisabled, + disabled: disabled, autoFocus: state.context.autoFocus, autoComplete: "off", autoCorrect: "off", autoCapitalize: "none", spellCheck: "false", - readOnly: isReadOnly, + readOnly: readOnly, placeholder: state.context.placeholder, id: dom.getInputId(state.context), type: "text", @@ -158,22 +153,22 @@ export function connect( defaultValue: state.context.inputValue, "aria-autocomplete": state.context.autoComplete ? "both" : "list", "aria-controls": isDialogPopup ? dom.getListId(state.context) : dom.getContentId(state.context), - "aria-expanded": isOpen, - "data-state": isOpen ? "open" : "closed", + "aria-expanded": open, + "data-state": open ? "open" : "closed", "aria-activedescendant": state.context.highlightedValue ? dom.getItemId(state.context, state.context.highlightedValue) : undefined, onClick() { if (!state.context.openOnClick) return - if (!isInteractive) return + if (!interactive) return send("INPUT.CLICK") }, onFocus() { - if (isDisabled) return + if (disabled) return send("INPUT.FOCUS") }, onBlur() { - if (isDisabled) return + if (disabled) return send("INPUT.BLUR") }, onChange(event) { @@ -181,7 +176,7 @@ export function connect( }, onKeyDown(event) { if (event.defaultPrevented) return - if (!isInteractive) return + if (!interactive) return const evt = getNativeEvent(event) if (evt.ctrlKey || evt.shiftKey || evt.isComposing) return @@ -192,33 +187,33 @@ export function connect( const keymap: EventKeyMap = { ArrowDown(event) { - if (!openOnKeyPress && !isOpen) return + if (!openOnKeyPress && !open) return send({ type: event.altKey ? "OPEN" : "INPUT.ARROW_DOWN", keypress }) event.preventDefault() }, ArrowUp() { - if (!openOnKeyPress && !isOpen) return + if (!openOnKeyPress && !open) return send({ type: event.altKey ? "CLOSE" : "INPUT.ARROW_UP", keypress }) event.preventDefault() }, Home(event) { if (isModifierKey) return send({ type: "INPUT.HOME", keypress }) - if (isOpen) { + if (open) { event.preventDefault() } }, End(event) { if (isModifierKey) return send({ type: "INPUT.END", keypress }) - if (isOpen) { + if (open) { event.preventDefault() } }, Enter(event) { if (evt.isComposing) return send({ type: "INPUT.ENTER", keypress }) - if (isOpen) { + if (open) { event.preventDefault() } const itemEl = dom.getHighlightedItemEl(state.context) @@ -244,20 +239,20 @@ export function connect( type: "button", tabIndex: isDialogPopup ? 0 : -1, "aria-label": translations.triggerLabel, - "aria-expanded": isOpen, - "data-state": isOpen ? "open" : "closed", - "aria-controls": isOpen ? dom.getContentId(state.context) : undefined, - disabled: isDisabled, - "data-readonly": dataAttr(isReadOnly), - "data-disabled": dataAttr(isDisabled), + "aria-expanded": open, + "data-state": open ? "open" : "closed", + "aria-controls": open ? dom.getContentId(state.context) : undefined, + disabled: disabled, + "data-readonly": dataAttr(readOnly), + "data-disabled": dataAttr(disabled), onClick(event) { const evt = getNativeEvent(event) - if (!isInteractive) return + if (!interactive) return if (!isLeftClick(evt)) return send("TRIGGER.CLICK") }, onPointerDown(event) { - if (!isInteractive) return + if (!interactive) return if (event.pointerType === "touch") return event.preventDefault() queueMicrotask(() => { @@ -301,8 +296,8 @@ export function connect( id: dom.getContentId(state.context), role: isDialogPopup ? "dialog" : "listbox", tabIndex: -1, - hidden: !isOpen, - "data-state": isOpen ? "open" : "closed", + hidden: !open, + "data-state": open ? "open" : "closed", "aria-labelledby": dom.getLabelId(state.context), "aria-multiselectable": state.context.multiple && !isDialogPopup ? true : undefined, onPointerDown(event) { @@ -324,12 +319,12 @@ export function connect( id: dom.getClearTriggerId(state.context), type: "button", tabIndex: -1, - disabled: isDisabled, + disabled: disabled, "aria-label": translations.clearTriggerLabel, "aria-controls": dom.getInputId(state.context), hidden: !state.context.value.length, onClick() { - if (!isInteractive) return + if (!interactive) return send({ type: "VALUE.CLEAR", src: "clear-trigger" }) }, }), @@ -346,19 +341,19 @@ export function connect( id: dom.getItemId(state.context, value), role: "option", tabIndex: -1, - "data-highlighted": dataAttr(itemState.isHighlighted), - "data-state": itemState.isSelected ? "checked" : "unchecked", - "aria-selected": itemState.isHighlighted, - "aria-disabled": itemState.isDisabled, - "data-disabled": dataAttr(itemState.isDisabled), + "data-highlighted": dataAttr(itemState.highlighted), + "data-state": itemState.selected ? "checked" : "unchecked", + "aria-selected": itemState.highlighted, + "aria-disabled": itemState.disabled, + "data-disabled": dataAttr(itemState.disabled), "data-value": itemState.value, onPointerMove() { - if (itemState.isDisabled) return + if (itemState.disabled) return send({ type: "ITEM.POINTER_MOVE", value }) }, onPointerLeave() { if (props.persistFocus) return - if (itemState.isDisabled) return + if (itemState.disabled) return const mouseMoved = state.previousEvent.type === "ITEM.POINTER_MOVE" if (!mouseMoved) return send({ type: "ITEM.POINTER_LEAVE", value }) @@ -367,7 +362,7 @@ export function connect( if (isDownloadingEvent(event)) return if (isOpeningInNewTab(event)) return if (isContextMenuEvent(event)) return - if (itemState.isDisabled) return + if (itemState.disabled) return send({ type: "ITEM.CLICK", src: "pointerup", value }) }, onTouchEnd(event) { @@ -383,8 +378,8 @@ export function connect( return normalize.element({ ...parts.itemText.attrs, dir: state.context.dir, - "data-disabled": dataAttr(itemState.isDisabled), - "data-highlighted": dataAttr(itemState.isHighlighted), + "data-disabled": dataAttr(itemState.disabled), + "data-highlighted": dataAttr(itemState.highlighted), }) }, getItemIndicatorProps(props) { @@ -393,8 +388,8 @@ export function connect( "aria-hidden": true, ...parts.itemIndicator.attrs, dir: state.context.dir, - "data-state": itemState.isSelected ? "checked" : "unchecked", - hidden: !itemState.isSelected, + "data-state": itemState.selected ? "checked" : "unchecked", + hidden: !itemState.selected, }) }, diff --git a/packages/machines/combobox/src/combobox.types.ts b/packages/machines/combobox/src/combobox.types.ts index 6bd495fac1..858b85e86c 100644 --- a/packages/machines/combobox/src/combobox.types.ts +++ b/packages/machines/combobox/src/combobox.types.ts @@ -278,15 +278,33 @@ export type Send = S.Send * -----------------------------------------------------------------------------*/ export interface ItemProps { + /** + * Whether hovering outside should clear the highlighted state + */ persistFocus?: boolean + /** + * The item to render + */ item: CollectionItem } export interface ItemState { + /** + * The value of the item + */ value: string - isDisabled: boolean - isSelected: boolean - isHighlighted: boolean + /** + * Whether the item is disabled + */ + disabled: boolean + /** + * Whether the item is selected + */ + selected: boolean + /** + * Whether the item is highlighted via pointer or keyboard navigation + */ + highlighted: boolean } export interface ItemGroupProps { @@ -301,15 +319,15 @@ export interface MachineApi(state: State, send: Send, normalize const disabled = state.context.disabled const readOnly = state.context.readOnly - const isInteractive = state.context.isInteractive + const interactive = state.context.isInteractive const min = state.context.min const max = state.context.max @@ -71,8 +71,8 @@ export function connect(state: State, send: Send, normalize const timeZone = state.context.timeZone const startOfWeek = state.context.startOfWeek - const isFocused = state.matches("focused") - const isOpen = state.matches("open") + const focused = state.matches("focused") + const open = state.matches("open") const isRangePicker = state.context.selectionMode === "range" const isDateUnavailableFn = state.context.isDateUnavailable @@ -120,12 +120,12 @@ export function connect(state: State, send: Send, normalize const { value, disabled } = props const normalized = focusedValue.set({ year: value }) const cellState = { - isFocused: focusedValue.year === props.value, - isSelectable: !isDateInvalid(normalized, min, max), - isSelected: !!selectedValue.find((date) => date.year === value), + focused: focusedValue.year === props.value, + selectable: !isDateInvalid(normalized, min, max), + selected: !!selectedValue.find((date) => date.year === value), valueText: value.toString(), - get isDisabled() { - return disabled || !cellState.isSelectable + get disabled() { + return disabled || !cellState.selectable }, } return cellState @@ -136,12 +136,12 @@ export function connect(state: State, send: Send, normalize const normalized = focusedValue.set({ month: value }) const formatter = getMonthFormatter(locale, timeZone) const cellState = { - isFocused: focusedValue.month === props.value, - isSelectable: !isDateInvalid(normalized, min, max), - isSelected: !!selectedValue.find((date) => date.month === value && date.year === focusedValue.year), + focused: focusedValue.month === props.value, + selectable: !isDateInvalid(normalized, min, max), + selected: !!selectedValue.find((date) => date.month === value && date.year === focusedValue.year), valueText: formatter.format(normalized.toDate(timeZone)), - get isDisabled() { - return disabled || !cellState.isSelectable + get disabled() { + return disabled || !cellState.selectable }, } return cellState @@ -156,28 +156,28 @@ export function connect(state: State, send: Send, normalize const end = visibleRange.start.add(unitDuration).subtract({ days: 1 }) const cellState = { - isInvalid: isDateInvalid(value, min, max), - isDisabled: disabled || isDateDisabled(value, visibleRange.start, end, min, max), - isSelected: selectedValue.some((date) => isDateEqual(value, date)), - isUnavailable: isDateUnavailable(value, isDateUnavailableFn, locale, min, max) && !disabled, - isOutsideRange: isDateOutsideVisibleRange(value, visibleRange.start, end), - isInRange: + invalid: isDateInvalid(value, min, max), + disabled: disabled || isDateDisabled(value, visibleRange.start, end, min, max), + selected: selectedValue.some((date) => isDateEqual(value, date)), + unavailable: isDateUnavailable(value, isDateUnavailableFn, locale, min, max) && !disabled, + outsideRange: isDateOutsideVisibleRange(value, visibleRange.start, end), + inRange: isRangePicker && (isDateWithinRange(value, selectedValue) || isDateWithinRange(value, hoveredRangeValue)), - isFirstInRange: isRangePicker && isDateEqual(value, selectedValue[0]), - isLastInRange: isRangePicker && isDateEqual(value, selectedValue[1]), - isToday: isTodayDate(value, timeZone), - isWeekend: isWeekend(value, locale), + firstInRange: isRangePicker && isDateEqual(value, selectedValue[0]), + lastInRange: isRangePicker && isDateEqual(value, selectedValue[1]), + today: isTodayDate(value, timeZone), + weekend: isWeekend(value, locale), formattedDate: formatter.format(value.toDate(timeZone)), - get isFocused() { - return isDateEqual(value, focusedValue) && !cellState.isOutsideRange + get focused() { + return isDateEqual(value, focusedValue) && !cellState.outsideRange }, get ariaLabel() { - if (cellState.isUnavailable) return `Not available. ${cellState.formattedDate}` - if (cellState.isSelected) return `Selected date. ${cellState.formattedDate}` + if (cellState.unavailable) return `Not available. ${cellState.formattedDate}` + if (cellState.selected) return `Selected date. ${cellState.formattedDate}` return `Choose ${cellState.formattedDate}` }, - get isSelectable() { - return !cellState.isDisabled && !cellState.isUnavailable + get selectable() { + return !cellState.disabled && !cellState.unavailable }, } return cellState @@ -189,8 +189,8 @@ export function connect(state: State, send: Send, normalize } return { - isFocused, - isOpen, + focused, + open, view: state.context.view, getRangePresetValue(preset) { return getDateRangePreset(preset, locale, timeZone) @@ -231,11 +231,9 @@ export function connect(state: State, send: Send, normalize setFocusedValue(value) { send({ type: "FOCUS.SET", value }) }, - open() { - send("OPEN") - }, - close() { - send("CLOSE") + setOpen(_open) { + if (_open === open) return + send(_open ? "OPEN" : "CLOSE") }, focusMonth, focusYear, @@ -270,7 +268,7 @@ export function connect(state: State, send: Send, normalize ...parts.root.attrs, dir: state.context.dir, id: dom.getRootId(state.context), - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(readOnly), }), @@ -279,7 +277,7 @@ export function connect(state: State, send: Send, normalize ...parts.label.attrs, dir: state.context.dir, htmlFor: dom.getInputId(state.context, 0), - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(readOnly), }), @@ -298,9 +296,9 @@ export function connect(state: State, send: Send, normalize contentProps: normalize.element({ ...parts.content.attrs, - hidden: !isOpen, + hidden: !open, dir: state.context.dir, - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", "data-placement": currentPlacement, id: dom.getContentId(state.context), role: "application", @@ -425,10 +423,10 @@ export function connect(state: State, send: Send, normalize return normalize.element({ ...parts.tableCell.attrs, role: "gridcell", - "aria-disabled": ariaAttr(!cellState.isSelectable), - "aria-selected": cellState.isSelected || cellState.isInRange, - "aria-invalid": ariaAttr(cellState.isInvalid), - "aria-current": cellState.isToday ? "date" : undefined, + "aria-disabled": ariaAttr(!cellState.selectable), + "aria-selected": cellState.selected || cellState.inRange, + "aria-invalid": ariaAttr(cellState.invalid), + "aria-current": cellState.today ? "date" : undefined, "data-value": value.toString(), }) }, @@ -440,28 +438,29 @@ export function connect(state: State, send: Send, normalize id: dom.getCellTriggerId(state.context, value.toString()), role: "button", dir: state.context.dir, - tabIndex: cellState.isFocused ? 0 : -1, + tabIndex: cellState.focused ? 0 : -1, "aria-label": cellState.ariaLabel, - "aria-disabled": ariaAttr(!cellState.isSelectable), - "aria-invalid": ariaAttr(cellState.isInvalid), - "data-disabled": dataAttr(!cellState.isSelectable), - "data-selected": dataAttr(cellState.isSelected), + "aria-disabled": ariaAttr(!cellState.selectable), + "aria-invalid": ariaAttr(cellState.invalid), + "data-disabled": dataAttr(!cellState.selectable), + "data-selected": dataAttr(cellState.selected), "data-value": value.toString(), "data-view": "day", - "data-today": dataAttr(cellState.isToday), - "data-focused": dataAttr(cellState.isFocused), - "data-unavailable": dataAttr(cellState.isUnavailable), - "data-range-start": dataAttr(cellState.isFirstInRange), - "data-range-end": dataAttr(cellState.isLastInRange), - "data-in-range": dataAttr(cellState.isInRange), - "data-outside-range": dataAttr(cellState.isOutsideRange), - "data-weekend": dataAttr(cellState.isWeekend), - onClick() { - if (!cellState.isSelectable) return + "data-today": dataAttr(cellState.today), + "data-focused": dataAttr(cellState.focused), + "data-unavailable": dataAttr(cellState.unavailable), + "data-range-start": dataAttr(cellState.firstInRange), + "data-range-end": dataAttr(cellState.lastInRange), + "data-in-range": dataAttr(cellState.inRange), + "data-outside-range": dataAttr(cellState.outsideRange), + "data-weekend": dataAttr(cellState.weekend), + onClick(event) { + if (event.defaultPrevented) return + if (!cellState.selectable) return send({ type: "CELL.CLICK", cell: "day", value }) }, onPointerMove(event) { - if (event.pointerType === "touch" || !cellState.isSelectable) return + if (event.pointerType === "touch" || !cellState.selectable) return const focus = event.currentTarget.ownerDocument.activeElement !== event.currentTarget if (hoveredValue && isEqualDay(value, hoveredValue)) return send({ type: "CELL.POINTER_MOVE", cell: "day", value, focus }) @@ -478,9 +477,9 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, colSpan: columns, role: "gridcell", - "aria-selected": ariaAttr(cellState.isSelected), - "data-selected": dataAttr(cellState.isSelected), - "aria-disabled": ariaAttr(!cellState.isSelectable), + "aria-selected": ariaAttr(cellState.selected), + "data-selected": dataAttr(cellState.selected), + "aria-disabled": ariaAttr(!cellState.selectable), "data-value": value, }) }, @@ -492,16 +491,17 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, role: "button", id: dom.getCellTriggerId(state.context, value.toString()), - "data-selected": dataAttr(cellState.isSelected), - "aria-disabled": ariaAttr(!cellState.isSelectable), - "data-disabled": dataAttr(!cellState.isSelectable), - "data-focused": dataAttr(cellState.isFocused), + "data-selected": dataAttr(cellState.selected), + "aria-disabled": ariaAttr(!cellState.selectable), + "data-disabled": dataAttr(!cellState.selectable), + "data-focused": dataAttr(cellState.focused), "aria-label": cellState.valueText, "data-view": "month", "data-value": value, - tabIndex: cellState.isFocused ? 0 : -1, - onClick() { - if (!cellState.isSelectable) return + tabIndex: cellState.focused ? 0 : -1, + onClick(event) { + if (event.defaultPrevented) return + if (!cellState.selectable) return send({ type: "CELL.CLICK", cell: "month", value }) }, }) @@ -516,9 +516,9 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, colSpan: columns, role: "gridcell", - "aria-selected": ariaAttr(cellState.isSelected), - "data-selected": dataAttr(cellState.isSelected), - "aria-disabled": ariaAttr(!cellState.isSelectable), + "aria-selected": ariaAttr(cellState.selected), + "data-selected": dataAttr(cellState.selected), + "aria-disabled": ariaAttr(!cellState.selectable), "data-value": value, }) }, @@ -530,16 +530,17 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, role: "button", id: dom.getCellTriggerId(state.context, value.toString()), - "data-selected": dataAttr(cellState.isSelected), - "data-focused": dataAttr(cellState.isFocused), - "aria-disabled": ariaAttr(!cellState.isSelectable), - "data-disabled": dataAttr(!cellState.isSelectable), + "data-selected": dataAttr(cellState.selected), + "data-focused": dataAttr(cellState.focused), + "aria-disabled": ariaAttr(!cellState.selectable), + "data-disabled": dataAttr(!cellState.selectable), "aria-label": cellState.valueText, "data-value": value, "data-view": "year", - tabIndex: cellState.isFocused ? 0 : -1, - onClick() { - if (!cellState.isSelectable) return + tabIndex: cellState.focused ? 0 : -1, + onClick(event) { + if (event.defaultPrevented) return + if (!cellState.selectable) return send({ type: "CELL.CLICK", cell: "year", value }) }, }) @@ -554,7 +555,8 @@ export function connect(state: State, send: Send, normalize type: "button", "aria-label": getNextTriggerLabel(view), disabled: disabled || !state.context.isNextVisibleRangeValid, - onClick() { + onClick(event) { + if (event.defaultPrevented) return send({ type: "GOTO.NEXT", view }) }, }) @@ -569,7 +571,8 @@ export function connect(state: State, send: Send, normalize type: "button", "aria-label": getPrevTriggerLabel(view), disabled: disabled || !state.context.isPrevVisibleRangeValid, - onClick() { + onClick(event) { + if (event.defaultPrevented) return send({ type: "GOTO.PREV", view }) }, }) @@ -582,7 +585,8 @@ export function connect(state: State, send: Send, normalize type: "button", "aria-label": "Clear dates", hidden: !state.context.value.length, - onClick() { + onClick(event) { + if (event.defaultPrevented) return send("VALUE.CLEAR") }, }), @@ -593,13 +597,14 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, type: "button", "data-placement": currentPlacement, - "aria-label": isOpen ? "Close calendar" : "Open calendar", + "aria-label": open ? "Close calendar" : "Open calendar", "aria-controls": dom.getContentId(state.context), - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", "aria-haspopup": "grid", disabled, - onClick() { - if (!isInteractive) return + onClick(event) { + if (event.defaultPrevented) return + if (!interactive) return send("TRIGGER.CLICK") }, }), @@ -614,8 +619,9 @@ export function connect(state: State, send: Send, normalize type: "button", disabled, "aria-label": getViewTriggerLabel(state.context.view), - onClick() { - if (!isInteractive) return + onClick(event) { + if (event.defaultPrevented) return + if (!interactive) return send("VIEW.CHANGE") }, }) @@ -641,7 +647,7 @@ export function connect(state: State, send: Send, normalize spellCheck: "false", dir: state.context.dir, name: state.context.name, - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", readOnly, disabled, placeholder: getInputPlaceholder(locale), @@ -660,7 +666,7 @@ export function connect(state: State, send: Send, normalize }, onKeyDown(event) { if (event.defaultPrevented) return - if (!isInteractive) return + if (!interactive) return const evt = getNativeEvent(event) if (evt.isComposing) return if (event.key !== "Enter") return @@ -714,7 +720,8 @@ export function connect(state: State, send: Send, normalize ? `select ${value[0].toString()} to ${value[1].toString()}` : `select ${value}`, type: "button", - onClick() { + onClick(event) { + if (event.defaultPrevented) return send({ type: "PRESET.CLICK", value }) }, }) diff --git a/packages/machines/date-picker/src/date-picker.types.ts b/packages/machines/date-picker/src/date-picker.types.ts index 1a8c502a61..d816ab6d36 100644 --- a/packages/machines/date-picker/src/date-picker.types.ts +++ b/packages/machines/date-picker/src/date-picker.types.ts @@ -317,11 +317,11 @@ export interface TableCellProps { } export interface TableCellState { - isFocused: boolean - isSelectable: boolean - isSelected: boolean + focused: boolean + selectable: boolean + selected: boolean valueText: string - readonly isDisabled: boolean + readonly disabled: boolean } export interface DayTableCellProps { @@ -331,20 +331,20 @@ export interface DayTableCellProps { } export interface DayTableCellState { - isInvalid: boolean - isDisabled: boolean - isSelected: boolean - isUnavailable: boolean - isOutsideRange: boolean - isInRange: boolean - isFirstInRange: boolean - isLastInRange: boolean - isToday: boolean - isWeekend: boolean + invalid: boolean + disabled: boolean + selected: boolean + unavailable: boolean + outsideRange: boolean + inRange: boolean + firstInRange: boolean + lastInRange: boolean + today: boolean + weekend: boolean formattedDate: string - readonly isFocused: boolean + readonly focused: boolean readonly ariaLabel: string - readonly isSelectable: boolean + readonly selectable: boolean } export interface TableProps { @@ -402,11 +402,11 @@ export interface MachineApi { /** * Whether the input is focused */ - isFocused: boolean + focused: boolean /** * Whether the date picker is open */ - isOpen: boolean + open: boolean /** * The current view of the date picker */ @@ -488,13 +488,9 @@ export interface MachineApi { */ clearValue(): void /** - * Function to open the calendar. - */ - open(): void - /** - * Function to close the calendar. + * Function to open or close the calendar. */ - close(): void + setOpen(open: boolean): void /** * Function to set the selected month. */ diff --git a/packages/machines/dialog/src/dialog.connect.ts b/packages/machines/dialog/src/dialog.connect.ts index 9debea931b..1aa91cf736 100644 --- a/packages/machines/dialog/src/dialog.connect.ts +++ b/packages/machines/dialog/src/dialog.connect.ts @@ -5,16 +5,14 @@ import type { MachineApi, Send, State } from "./dialog.types" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { const ariaLabel = state.context["aria-label"] - const isOpen = state.matches("open") + const open = state.matches("open") const rendered = state.context.renderedElements return { - isOpen, - open() { - send("OPEN") - }, - close() { - send("CLOSE") + open, + setOpen(_open) { + if (_open === open) return + send(_open ? "OPEN" : "CLOSE") }, triggerProps: normalize.button({ @@ -23,10 +21,11 @@ export function connect(state: State, send: Send, normalize id: dom.getTriggerId(state.context), "aria-haspopup": "dialog", type: "button", - "aria-expanded": isOpen, - "data-state": isOpen ? "open" : "closed", + "aria-expanded": open, + "data-state": open ? "open" : "closed", "aria-controls": dom.getContentId(state.context), - onClick() { + onClick(event) { + if (event.defaultPrevented) return send("TOGGLE") }, }), @@ -34,9 +33,9 @@ export function connect(state: State, send: Send, normalize backdropProps: normalize.element({ ...parts.backdrop.attrs, dir: state.context.dir, - hidden: !isOpen, + hidden: !open, id: dom.getBackdropId(state.context), - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", }), positionerProps: normalize.element({ @@ -44,7 +43,7 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, id: dom.getPositionerId(state.context), style: { - pointerEvents: isOpen ? undefined : "none", + pointerEvents: open ? undefined : "none", }, }), @@ -52,10 +51,10 @@ export function connect(state: State, send: Send, normalize ...parts.content.attrs, dir: state.context.dir, role: state.context.role, - hidden: !isOpen, + hidden: !open, id: dom.getContentId(state.context), tabIndex: -1, - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", "aria-modal": true, "aria-label": ariaLabel || undefined, "aria-labelledby": ariaLabel || !rendered.title ? undefined : dom.getTitleId(state.context), @@ -80,6 +79,7 @@ export function connect(state: State, send: Send, normalize id: dom.getCloseTriggerId(state.context), type: "button", onClick(event) { + if (event.defaultPrevented) return event.stopPropagation() send("CLOSE") }, diff --git a/packages/machines/dialog/src/dialog.types.ts b/packages/machines/dialog/src/dialog.types.ts index afbe63ba6e..47b30de38f 100644 --- a/packages/machines/dialog/src/dialog.types.ts +++ b/packages/machines/dialog/src/dialog.types.ts @@ -121,15 +121,11 @@ export interface MachineApi { /** * Whether the dialog is open */ - isOpen: boolean - /** - * Function to open the dialog - */ - open(): void + open: boolean /** - * Function to close the dialog + * Function to open or close the dialog */ - close(): void + setOpen(open: boolean): void triggerProps: T["button"] backdropProps: T["element"] diff --git a/packages/machines/editable/src/editable.connect.ts b/packages/machines/editable/src/editable.connect.ts index 51fb7544fa..8df6febf9d 100644 --- a/packages/machines/editable/src/editable.connect.ts +++ b/packages/machines/editable/src/editable.connect.ts @@ -6,24 +6,24 @@ import { dom } from "./editable.dom" import type { MachineApi, Send, State } from "./editable.types" export function connect
- - {api.title} - {api.description} - Close -
{api.title}
{api.description}
{api.currentStep.title}
+ - + {api.type === "loading" && } {api.title} @@ -47,7 +34,7 @@ const ToastItem = defineComponent({ - + ) } }, diff --git a/examples/vue-ts/src/pages/tooltip.tsx b/examples/vue-ts/src/pages/tooltip.tsx index 824574adf3..a063f1ccc8 100644 --- a/examples/vue-ts/src/pages/tooltip.tsx +++ b/examples/vue-ts/src/pages/tooltip.tsx @@ -21,7 +21,7 @@ export default defineComponent({ Hover me - {api.isOpen && ( + {api.open && ( @@ -32,7 +32,7 @@ export default defineComponent({ )} Over me - {api2.isOpen && ( + {api2.open && ( diff --git a/packages/docs/data/api.json b/packages/docs/data/api.json index 2f23dd59b0..2365af393a 100644 --- a/packages/docs/data/api.json +++ b/packages/docs/data/api.json @@ -70,14 +70,10 @@ }, "avatar": { "api": { - "isLoaded": { + "loaded": { "type": "boolean", "description": "Whether the image is loaded." }, - "showFallback": { - "type": "boolean", - "description": "Whether the fallback is shown." - }, "setSrc": { "type": "(src: string) => void", "description": "Function to set new src." @@ -121,9 +117,9 @@ "type": "number", "description": "The current scroll progress of the carousel" }, - "isAutoplay": { + "autoPlaying": { "type": "boolean", - "description": "Whether the carousel is currently auto-playing" + "description": "Whether the carousel is auto playing" }, "canScrollNext": { "type": "boolean", @@ -209,19 +205,19 @@ }, "checkbox": { "api": { - "isChecked": { + "checked": { "type": "boolean", "description": "Whether the checkbox is checked" }, - "isDisabled": { + "disabled": { "type": "boolean", "description": "Whether the checkbox is disabled" }, - "isIndeterminate": { + "indeterminate": { "type": "boolean", "description": "Whether the checkbox is indeterminate" }, - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the checkbox is focused" }, @@ -245,27 +241,31 @@ }, "disabled": { "type": "boolean", - "description": "If `true`, the checkbox will be disabled" + "description": "Whether the checkbox is disabled" }, "invalid": { "type": "boolean", - "description": "If `true`, the checkbox is marked as invalid." + "description": "Whether the checkbox is invalid" }, "required": { "type": "boolean", - "description": "If `true`, the checkbox input is marked as required," + "description": "Whether the checkbox is required" }, "checked": { "type": "CheckedState", - "description": "If `true`, the checkbox will be checked." + "description": "The checked state of the checkbox" + }, + "readOnly": { + "type": "boolean", + "description": "Whether the checkbox is read-only" }, "onCheckedChange": { "type": "(details: CheckedChangeDetails) => void", - "description": "The callback invoked when the checked state of the `Checkbox` changes." + "description": "The callback invoked when the checked state changes." }, "name": { "type": "string", - "description": "The name of the input field in a checkbox. Useful for form submission." + "description": "The name of the input field in a checkbox.\nUseful for form submission." }, "form": { "type": "string", @@ -293,7 +293,7 @@ }, "clipboard": { "api": { - "isCopied": { + "copied": { "type": "boolean", "description": "Whether the value has been copied to the clipboard" }, @@ -339,25 +339,21 @@ }, "collapsible": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the collapsible is open." }, - "isVisible": { + "visible": { "type": "boolean", "description": "Whether the collapsible is visible (open or closing)" }, - "isDisabled": { + "disabled": { "type": "boolean", "description": "Whether the collapsible is disabled" }, - "open": { - "type": "() => void", - "description": "Function to open the collapsible." - }, - "close": { - "type": "() => void", - "description": "Function to close the collapsible." + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the collapsible." } }, "context": { @@ -402,11 +398,11 @@ }, "color-picker": { "api": { - "isDragging": { + "dragging": { "type": "boolean", "description": "Whether the color picker is being dragged" }, - "isOpen": { + "open": { "type": "boolean", "description": "Whether the color picker is open" }, @@ -446,13 +442,9 @@ "type": "(value: number) => void", "description": "Function to set the color alpha" }, - "open": { - "type": "() => void", - "description": "Function to open the color picker" - }, - "close": { - "type": "() => void", - "description": "Function to close the color picker" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the color picker" } }, "context": { @@ -544,15 +536,15 @@ }, "combobox": { "api": { - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the combobox is focused" }, - "isOpen": { + "open": { "type": "boolean", "description": "Whether the combobox is open" }, - "isInputValueEmpty": { + "inputEmpty": { "type": "boolean", "description": "Whether the combobox input value is empty" }, @@ -612,13 +604,9 @@ "type": "(props: ItemProps) => ItemState", "description": "Returns the state of a combobox item" }, - "open": { - "type": "() => void", - "description": "Function to open the combobox" - }, - "close": { - "type": "() => void", - "description": "Function to close the combobox" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the combobox" }, "collection": { "type": "Collection", @@ -795,11 +783,11 @@ }, "date-picker": { "api": { - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the input is focused" }, - "isOpen": { + "open": { "type": "boolean", "description": "Whether the date picker is open" }, @@ -883,13 +871,9 @@ "type": "() => void", "description": "Clears the selected date(s)." }, - "open": { - "type": "() => void", - "description": "Function to open the calendar." - }, - "close": { - "type": "() => void", - "description": "Function to close the calendar." + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the calendar." }, "focusMonth": { "type": "(month: number) => void", @@ -1076,17 +1060,13 @@ }, "dialog": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the dialog is open" }, - "open": { - "type": "() => void", - "description": "Function to open the dialog" - }, - "close": { - "type": "() => void", - "description": "Function to close the dialog" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the dialog" } }, "context": { @@ -1180,11 +1160,11 @@ }, "editable": { "api": { - "isEditing": { + "editing": { "type": "boolean", "description": "Whether the editable is in edit mode" }, - "isValueEmpty": { + "empty": { "type": "boolean", "description": "Whether the editable value is empty" }, @@ -1325,15 +1305,15 @@ }, "file-upload": { "api": { - "isDragging": { + "dragging": { "type": "boolean", "description": "Whether the user is dragging something over the root element" }, - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the user is focused on the dropzone element" }, - "open": { + "openFilePicker": { "type": "() => void", "description": "Function to open the file dialog" }, @@ -1449,15 +1429,19 @@ }, "floating-panel": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the panel is open" }, - "isDragging": { + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the panel" + }, + "dragging": { "type": "boolean", "description": "Whether the panel is being dragged" }, - "isResizing": { + "resizing": { "type": "boolean", "description": "Whether the panel is being resized" } @@ -1556,18 +1540,14 @@ }, "hover-card": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the hover card is open" }, - "open": { - "type": "() => void", + "setOpen": { + "type": "(open: boolean) => void", "description": "Function to open the hover card" }, - "close": { - "type": "() => void", - "description": "Function to close the hover card" - }, "reposition": { "type": "(options?: Partial) => void", "description": "Function to reposition the popover" @@ -1619,17 +1599,13 @@ }, "menu": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the menu is open" }, - "open": { - "type": "() => void", - "description": "Function to open the menu" - }, - "close": { - "type": "() => void", - "description": "Function to close the menu" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the menu" }, "highlightedValue": { "type": "string", @@ -1746,15 +1722,15 @@ }, "number-input": { "api": { - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the input is focused." }, - "isInvalid": { + "invalid": { "type": "boolean", "description": "Whether the input is invalid." }, - "isValueEmpty": { + "empty": { "type": "boolean", "description": "Whether the input value is empty." }, @@ -1939,14 +1915,6 @@ "type": "(data: V[]) => V[]", "description": "Function to slice an array of data based on the current page." }, - "isFirstPage": { - "type": "boolean", - "description": "Whether the current page is the first page." - }, - "isLastPage": { - "type": "boolean", - "description": "Whether the current page is the last page." - }, "setCount": { "type": "(count: number) => void", "description": "Function to set the total number of pages." @@ -2019,7 +1987,7 @@ "type": "string", "description": "The value of the input as a string." }, - "isValueComplete": { + "complete": { "type": "boolean", "description": "Whether all inputs are filled." }, @@ -2134,17 +2102,13 @@ "type": "boolean", "description": "Whether the popover is portalled" }, - "isOpen": { + "open": { "type": "boolean", "description": "Whether the popover is open" }, - "open": { - "type": "() => void", - "description": "Function to open the popover" - }, - "close": { - "type": "() => void", - "description": "Function to close the popover" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the popover" }, "reposition": { "type": "(options?: Partial) => void", @@ -2231,7 +2195,7 @@ }, "presence": { "api": { - "isPresent": { + "present": { "type": "boolean", "description": "Whether the node is present in the DOM." }, @@ -2351,6 +2315,10 @@ "type": "boolean", "description": "If `true`, the radio group will be disabled" }, + "readOnly": { + "type": "boolean", + "description": "Whether the checkbox is read-only" + }, "onValueChange": { "type": "(details: ValueChangeDetails) => void", "description": "Function called once a radio is checked" @@ -2384,7 +2352,7 @@ "type": "() => void", "description": "Clears the value of the rating group" }, - "isHovering": { + "hovering": { "type": "boolean", "description": "Whether the rating group is being hovered" }, @@ -2475,15 +2443,15 @@ }, "select": { "api": { - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the select is focused" }, - "isOpen": { + "open": { "type": "boolean", "description": "Whether the select is open" }, - "isValueEmpty": { + "empty": { "type": "boolean", "description": "Whether the select value is empty" }, @@ -2535,13 +2503,9 @@ "type": "(props: ItemProps) => ItemState", "description": "Returns the state of a select item" }, - "open": { - "type": "() => void", - "description": "Function to open the select" - }, - "close": { - "type": "() => void", - "description": "Function to close the select" + "setOpen": { + "type": "(open: boolean) => void", + "description": "Function to open or close the select" }, "collection": { "type": "Collection", @@ -2662,11 +2626,11 @@ }, "signature-pad": { "api": { - "isEmpty": { + "empty": { "type": "boolean", "description": "Whether the signature pad is empty." }, - "isDrawing": { + "drawing": { "type": "boolean", "description": "Whether the user is currently drawing." }, @@ -2733,11 +2697,11 @@ "type": "number[]", "description": "The value of the slider." }, - "isDragging": { + "dragging": { "type": "boolean", "description": "Whether the slider is being dragged." }, - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the slider is focused." }, @@ -2840,7 +2804,7 @@ "description": "Function invoked when the slider's focused index changes" }, "getAriaValueText": { - "type": "(value: number, index: number) => string", + "type": "(details: ValueTextDetails) => string", "description": "Function that returns a human readable value for the slider thumb" }, "min": { @@ -2892,11 +2856,11 @@ }, "splitter": { "api": { - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the splitter is focused." }, - "isDragging": { + "dragging": { "type": "boolean", "description": "Whether the splitter is being dragged." }, @@ -2959,15 +2923,15 @@ }, "switch": { "api": { - "isChecked": { + "checked": { "type": "boolean", "description": "Whether the checkbox is checked" }, - "isDisabled": { + "disabled": { "type": "boolean", "description": "Whether the checkbox is disabled" }, - "isFocused": { + "focused": { "type": "boolean", "description": "Whether the checkbox is focused" }, @@ -3001,6 +2965,10 @@ "type": "boolean", "description": "If `true`, the switch input is marked as required," }, + "readOnly": { + "type": "boolean", + "description": "Whether the switch is read-only" + }, "onCheckedChange": { "type": "(details: CheckedChangeDetails) => void", "description": "Function to call when the switch is clicked." @@ -3117,7 +3085,7 @@ }, "tags-input": { "api": { - "isEmpty": { + "empty": { "type": "boolean", "description": "Whether the tags are empty" }, @@ -3137,7 +3105,7 @@ "type": "number", "description": "The number of the tags." }, - "isAtMax": { + "atMax": { "type": "boolean", "description": "Whether the tags have reached the max limit." }, @@ -3357,18 +3325,14 @@ }, "tooltip": { "api": { - "isOpen": { + "open": { "type": "boolean", "description": "Whether the tooltip is open." }, - "open": { - "type": "() => void", + "setOpen": { + "type": "(open: boolean) => void", "description": "Function to open the tooltip." }, - "close": { - "type": "() => void", - "description": "Function to close the tooltip." - }, "reposition": { "type": "(options?: Partial) => void", "description": "Function to reposition the popover" diff --git a/packages/machines/accordion/src/accordion.connect.ts b/packages/machines/accordion/src/accordion.connect.ts index 0314780020..5e9b6219a3 100644 --- a/packages/machines/accordion/src/accordion.connect.ts +++ b/packages/machines/accordion/src/accordion.connect.ts @@ -20,9 +20,9 @@ export function connect(state: State, send: Send, normalize function getItemState(props: ItemProps): ItemState { return { - isOpen: value.includes(props.value), - isFocused: focusedValue === props.value, - isDisabled: Boolean(props.disabled ?? state.context.disabled), + expanded: value.includes(props.value), + focused: focusedValue === props.value, + disabled: Boolean(props.disabled ?? state.context.disabled), } } @@ -45,9 +45,9 @@ export function connect(state: State, send: Send, normalize ...parts.item.attrs, dir: state.context.dir, id: dom.getItemId(state.context, props.value), - "data-state": itemState.isOpen ? "open" : "closed", - "data-focus": dataAttr(itemState.isFocused), - "data-disabled": dataAttr(itemState.isDisabled), + "data-state": itemState.expanded ? "open" : "closed", + "data-focus": dataAttr(itemState.focused), + "data-disabled": dataAttr(itemState.disabled), "data-orientation": state.context.orientation, }) }, @@ -60,10 +60,10 @@ export function connect(state: State, send: Send, normalize role: "region", id: dom.getItemContentId(state.context, props.value), "aria-labelledby": dom.getItemTriggerId(state.context, props.value), - hidden: !itemState.isOpen, - "data-state": itemState.isOpen ? "open" : "closed", - "data-disabled": dataAttr(itemState.isDisabled), - "data-focus": dataAttr(itemState.isFocused), + hidden: !itemState.expanded, + "data-state": itemState.expanded ? "open" : "closed", + "data-disabled": dataAttr(itemState.disabled), + "data-focus": dataAttr(itemState.focused), "data-orientation": state.context.orientation, }) }, @@ -74,9 +74,9 @@ export function connect(state: State, send: Send, normalize ...parts.itemIndicator.attrs, dir: state.context.dir, "aria-hidden": true, - "data-state": itemState.isOpen ? "open" : "closed", - "data-disabled": dataAttr(itemState.isDisabled), - "data-focus": dataAttr(itemState.isFocused), + "data-state": itemState.expanded ? "open" : "closed", + "data-disabled": dataAttr(itemState.disabled), + "data-focus": dataAttr(itemState.focused), "data-orientation": state.context.orientation, }) }, @@ -91,22 +91,22 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, id: dom.getItemTriggerId(state.context, value), "aria-controls": dom.getItemContentId(state.context, value), - "aria-expanded": itemState.isOpen, - disabled: itemState.isDisabled, + "aria-expanded": itemState.expanded, + disabled: itemState.disabled, "data-orientation": state.context.orientation, - "aria-disabled": itemState.isDisabled, - "data-state": itemState.isOpen ? "open" : "closed", + "aria-disabled": itemState.disabled, + "data-state": itemState.expanded ? "open" : "closed", "data-ownedby": dom.getRootId(state.context), onFocus() { - if (itemState.isDisabled) return + if (itemState.disabled) return send({ type: "TRIGGER.FOCUS", value }) }, onBlur() { - if (itemState.isDisabled) return + if (itemState.disabled) return send("TRIGGER.BLUR") }, onClick(event) { - if (itemState.isDisabled) return + if (itemState.disabled) return if (isSafari()) { event.currentTarget.focus() } @@ -114,7 +114,7 @@ export function connect(state: State, send: Send, normalize }, onKeyDown(event) { if (event.defaultPrevented) return - if (itemState.isDisabled) return + if (itemState.disabled) return const keyMap: EventKeyMap = { ArrowDown() { diff --git a/packages/machines/accordion/src/accordion.types.ts b/packages/machines/accordion/src/accordion.types.ts index 93276bd2d1..7f98b6cfe5 100644 --- a/packages/machines/accordion/src/accordion.types.ts +++ b/packages/machines/accordion/src/accordion.types.ts @@ -50,11 +50,11 @@ interface PublicContext extends DirectionProperty, CommonProperties { /** * The callback fired when the state of opened/closed accordion items changes. */ - onValueChange?: (details: ValueChangeDetails) => void + onValueChange?(details: ValueChangeDetails): void /** * The callback fired when the focused accordion item changes. */ - onFocusChange?: (details: FocusChangeDetails) => void + onFocusChange?(details: FocusChangeDetails): void /** * The orientation of the accordion items. */ @@ -94,14 +94,29 @@ export type Send = S.Send * -----------------------------------------------------------------------------*/ export interface ItemProps { + /** + * The value of the accordion item. + */ value: string + /** + * Whether the accordion item is disabled. + */ disabled?: boolean } export interface ItemState { - isOpen: boolean - isFocused: boolean - isDisabled: boolean + /** + * Whether the accordion item is expanded. + */ + expanded: boolean + /** + * Whether the accordion item is focused. + */ + focused: boolean + /** + * Whether the accordion item is disabled. + */ + disabled: boolean } export interface MachineApi { @@ -120,7 +135,8 @@ export interface MachineApi { /** * Gets the state of an accordion item. */ - getItemState: (props: ItemProps) => ItemState + getItemState(props: ItemProps): ItemState + rootProps: T["element"] getItemProps(props: ItemProps): T["element"] getItemContentProps(props: ItemProps): T["element"] diff --git a/packages/machines/avatar/src/avatar.connect.ts b/packages/machines/avatar/src/avatar.connect.ts index 2b146a8686..9d8ec7535a 100644 --- a/packages/machines/avatar/src/avatar.connect.ts +++ b/packages/machines/avatar/src/avatar.connect.ts @@ -4,12 +4,9 @@ import { dom } from "./avatar.dom" import type { MachineApi, Send, State } from "./avatar.types" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { - const isLoaded = state.matches("loaded") - const showFallback = !isLoaded - + const loaded = state.matches("loaded") return { - isLoaded, - showFallback, + loaded, setSrc(src) { send({ type: "SRC.SET", src }) }, @@ -28,10 +25,10 @@ export function connect(state: State, send: Send, normalize imageProps: normalize.img({ ...parts.image.attrs, - hidden: !isLoaded, + hidden: !loaded, dir: state.context.dir, id: dom.getImageId(state.context), - "data-state": isLoaded ? "visible" : "hidden", + "data-state": loaded ? "visible" : "hidden", onLoad() { send({ type: "IMG.LOADED", src: "element" }) }, @@ -44,8 +41,8 @@ export function connect(state: State, send: Send, normalize ...parts.fallback.attrs, dir: state.context.dir, id: dom.getFallbackId(state.context), - hidden: isLoaded, - "data-state": isLoaded ? "hidden" : "visible", + hidden: loaded, + "data-state": loaded ? "hidden" : "visible", }), } } diff --git a/packages/machines/avatar/src/avatar.types.ts b/packages/machines/avatar/src/avatar.types.ts index 28ff0eef10..6421d361e1 100644 --- a/packages/machines/avatar/src/avatar.types.ts +++ b/packages/machines/avatar/src/avatar.types.ts @@ -5,8 +5,10 @@ import type { CommonProperties, DirectionProperty, PropTypes, RequiredBy } from * Callback details * -----------------------------------------------------------------------------*/ +export type LoadStatus = "error" | "loaded" + export interface StatusChangeDetails { - status: "loaded" | "error" + status: LoadStatus } /* ----------------------------------------------------------------------------- @@ -44,11 +46,7 @@ export interface MachineApi { /** * Whether the image is loaded. */ - isLoaded: boolean - /** - * Whether the fallback is shown. - */ - showFallback: boolean + loaded: boolean /** * Function to set new src. */ diff --git a/packages/machines/avatar/src/index.ts b/packages/machines/avatar/src/index.ts index 53c0204402..4ecd5fdbc8 100644 --- a/packages/machines/avatar/src/index.ts +++ b/packages/machines/avatar/src/index.ts @@ -2,4 +2,4 @@ export { anatomy } from "./avatar.anatomy" export { connect } from "./avatar.connect" export { machine } from "./avatar.machine" export * from "./avatar.props" -export type { MachineApi as Api, UserDefinedContext as Context, StatusChangeDetails } from "./avatar.types" +export type { MachineApi as Api, UserDefinedContext as Context, StatusChangeDetails, LoadStatus } from "./avatar.types" diff --git a/packages/machines/carousel/src/carousel.connect.ts b/packages/machines/carousel/src/carousel.connect.ts index b199e93c06..810902145b 100644 --- a/packages/machines/carousel/src/carousel.connect.ts +++ b/packages/machines/carousel/src/carousel.connect.ts @@ -2,14 +2,14 @@ import { dataAttr, isDom } from "@zag-js/dom-query" import type { NormalizeProps, PropTypes } from "@zag-js/types" import { parts } from "./carousel.anatomy" import { dom } from "./carousel.dom" -import type { MachineApi, Send, IndicatorProps, ItemProps, State, ItemState } from "./carousel.types" +import type { IndicatorProps, ItemProps, ItemState, MachineApi, Send, State } from "./carousel.types" import { getSlidesInView } from "./utils/get-slide-in-view" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { const canScrollNext = state.context.canScrollNext const canScrollPrev = state.context.canScrollPrev - const isHorizontal = state.context.isHorizontal - const isAutoplay = state.matches("autoplay") + const horizontal = state.context.isHorizontal + const autoPlaying = state.matches("autoplay") const activeSnap = state.context.scrollSnaps[state.context.index] const slidesInView = isDom() ? getSlidesInView(state.context)(activeSnap) : [] @@ -18,38 +18,32 @@ export function connect(state: State, send: Send, normalize const { index } = props return { valueText: `Slide ${index + 1}`, - isCurrent: index === state.context.index, - isNext: index === state.context.index + 1, - isPrevious: index === state.context.index - 1, - isInView: slidesInView.includes(index), + current: index === state.context.index, + next: index === state.context.index + 1, + previous: index === state.context.index - 1, + inView: slidesInView.includes(index), } } return { index: state.context.index, scrollProgress: state.context.scrollProgress, - isAutoplay, + autoPlaying, canScrollNext, canScrollPrev, - scrollTo(index, jump) { send({ type: "GOTO", index, jump }) }, - scrollToNext() { send("NEXT") }, - scrollToPrevious() { send("PREV") }, - getItemState: getItemState, - play() { send("PLAY") }, - pause() { send("PAUSE") }, @@ -82,8 +76,8 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, style: { display: "flex", - flexDirection: isHorizontal ? "row" : "column", - [isHorizontal ? "height" : "width"]: "auto", + flexDirection: horizontal ? "row" : "column", + [horizontal ? "height" : "width"]: "auto", gap: "var(--slide-spacing)", transform: state.context.translateValue, transitionProperty: "transform", @@ -101,8 +95,8 @@ export function connect(state: State, send: Send, normalize ...parts.item.attrs, id: dom.getItemId(state.context, index), dir: state.context.dir, - "data-current": dataAttr(sliderState.isCurrent), - "data-inview": dataAttr(sliderState.isInView), + "data-current": dataAttr(sliderState.current), + "data-inview": dataAttr(sliderState.inView), role: "group", "aria-roledescription": "slide", "data-orientation": state.context.orientation, @@ -110,7 +104,7 @@ export function connect(state: State, send: Send, normalize style: { position: "relative", flex: "0 0 var(--slide-size)", - [isHorizontal ? "minWidth" : "minHeight"]: "0px", + [horizontal ? "minWidth" : "minHeight"]: "0px", }, }) }, diff --git a/packages/machines/carousel/src/carousel.types.ts b/packages/machines/carousel/src/carousel.types.ts index b383c1bf8e..b92e9df1bd 100644 --- a/packages/machines/carousel/src/carousel.types.ts +++ b/packages/machines/carousel/src/carousel.types.ts @@ -98,15 +98,33 @@ export type Send = S.Send * -----------------------------------------------------------------------------*/ export interface ItemProps { + /** + * The index of the item. + */ index: number } export interface ItemState { + /** + * The text value of the item. Used for accessibility. + */ valueText: string - isCurrent: boolean - isNext: boolean - isPrevious: boolean - isInView: boolean + /** + * Whether the item is the current item in the carousel + */ + current: boolean + /** + * Whether the item is the next item in the carousel + */ + next: boolean + /** + * Whether the item is the previous item in the carousel + */ + previous: boolean + /** + * Whether the item is in view + */ + inView: boolean } export interface IndicatorProps { @@ -124,9 +142,9 @@ export interface MachineApi { */ scrollProgress: number /** - * Whether the carousel is currently auto-playing + * Whether the carousel is auto playing */ - isAutoplay: boolean + autoPlaying: boolean /** * Whether the carousel is can scroll to the next slide */ diff --git a/packages/machines/checkbox/package.json b/packages/machines/checkbox/package.json index e1a9a13721..e7f490b20e 100644 --- a/packages/machines/checkbox/package.json +++ b/packages/machines/checkbox/package.json @@ -41,7 +41,6 @@ "@zag-js/types": "workspace:*", "@zag-js/dom-query": "workspace:*", "@zag-js/dom-event": "workspace:*", - "@zag-js/visually-hidden": "workspace:*", "@zag-js/form-utils": "workspace:*", "@zag-js/utils": "workspace:*" }, diff --git a/packages/machines/checkbox/src/checkbox.connect.ts b/packages/machines/checkbox/src/checkbox.connect.ts index 307448656d..ff16d983b3 100644 --- a/packages/machines/checkbox/src/checkbox.connect.ts +++ b/packages/machines/checkbox/src/checkbox.connect.ts @@ -1,38 +1,39 @@ -import { dataAttr } from "@zag-js/dom-query" +import { dataAttr, visuallyHiddenStyle } from "@zag-js/dom-query" import type { NormalizeProps, PropTypes } from "@zag-js/types" -import { visuallyHiddenStyle } from "@zag-js/visually-hidden" import { parts } from "./checkbox.anatomy" import { dom } from "./checkbox.dom" -import type { CheckedState, MachineApi, Send, State } from "./checkbox.types" +import type { MachineApi, Send, State } from "./checkbox.types" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { - const isDisabled = state.context.isDisabled - const isFocused = !isDisabled && state.context.focused - const isChecked = state.context.isChecked - const isIndeterminate = state.context.isIndeterminate + const disabled = state.context.isDisabled + const focused = !disabled && state.context.focused + const checked = state.context.isChecked + const indeterminate = state.context.isIndeterminate + const readOnly = state.context.readOnly const dataAttrs = { "data-active": dataAttr(state.context.active), - "data-focus": dataAttr(isFocused), + "data-focus": dataAttr(focused), + "data-readonly": dataAttr(readOnly), "data-hover": dataAttr(state.context.hovered), - "data-disabled": dataAttr(isDisabled), - "data-state": isIndeterminate ? "indeterminate" : state.context.checked ? "checked" : "unchecked", + "data-disabled": dataAttr(disabled), + "data-state": indeterminate ? "indeterminate" : state.context.checked ? "checked" : "unchecked", "data-invalid": dataAttr(state.context.invalid), } return { - isChecked, - isDisabled, - isIndeterminate, - isFocused, + checked, + disabled, + indeterminate, + focused, checkedState: state.context.checked, - setChecked(checked: CheckedState) { + setChecked(checked) { send({ type: "CHECKED.SET", checked, isTrusted: false }) }, toggleChecked() { - send({ type: "CHECKED.TOGGLE", checked: isChecked, isTrusted: false }) + send({ type: "CHECKED.TOGGLE", checked: checked, isTrusted: false }) }, rootProps: normalize.label({ @@ -42,11 +43,11 @@ export function connect(state: State, send: Send, normalize id: dom.getRootId(state.context), htmlFor: dom.getHiddenInputId(state.context), onPointerMove() { - if (isDisabled) return + if (disabled) return send({ type: "CONTEXT.SET", context: { hovered: true } }) }, onPointerLeave() { - if (isDisabled) return + if (disabled) return send({ type: "CONTEXT.SET", context: { hovered: false } }) }, onClick(event) { @@ -75,16 +76,16 @@ export function connect(state: State, send: Send, normalize ...parts.indicator.attrs, ...dataAttrs, dir: state.context.dir, - hidden: !isIndeterminate && !state.context.checked, + hidden: !indeterminate && !state.context.checked, }), hiddenInputProps: normalize.input({ id: dom.getHiddenInputId(state.context), type: "checkbox", required: state.context.required, - defaultChecked: isChecked, - disabled: isDisabled, - "data-disabled": dataAttr(isDisabled), + defaultChecked: checked, + disabled: disabled, + "data-disabled": dataAttr(disabled), "aria-labelledby": dom.getLabelId(state.context), "aria-invalid": state.context.invalid, name: state.context.name, @@ -92,6 +93,11 @@ export function connect(state: State, send: Send, normalize value: state.context.value, style: visuallyHiddenStyle, onChange(event) { + if (readOnly) { + event.preventDefault() + return + } + const checked = event.currentTarget.checked send({ type: "CHECKED.SET", checked, isTrusted: true }) }, diff --git a/packages/machines/checkbox/src/checkbox.props.ts b/packages/machines/checkbox/src/checkbox.props.ts index f0072b357b..46e1903a4f 100644 --- a/packages/machines/checkbox/src/checkbox.props.ts +++ b/packages/machines/checkbox/src/checkbox.props.ts @@ -13,6 +13,7 @@ export const props = createProps()([ "invalid", "name", "onCheckedChange", + "readOnly", "required", "value", ]) diff --git a/packages/machines/checkbox/src/checkbox.types.ts b/packages/machines/checkbox/src/checkbox.types.ts index b41e80e46f..d3be097554 100644 --- a/packages/machines/checkbox/src/checkbox.types.ts +++ b/packages/machines/checkbox/src/checkbox.types.ts @@ -28,27 +28,32 @@ interface PublicContext extends DirectionProperty, CommonProperties { */ ids?: ElementIds /** - * If `true`, the checkbox will be disabled + * Whether the checkbox is disabled */ disabled?: boolean /** - * If `true`, the checkbox is marked as invalid. + * Whether the checkbox is invalid */ invalid?: boolean /** - * If `true`, the checkbox input is marked as required, + * Whether the checkbox is required */ required?: boolean /** - * If `true`, the checkbox will be checked. + * The checked state of the checkbox */ checked: CheckedState /** - * The callback invoked when the checked state of the `Checkbox` changes. + * Whether the checkbox is read-only + */ + readOnly?: boolean + /** + * The callback invoked when the checked state changes. */ onCheckedChange?(details: CheckedChangeDetails): void /** - * The name of the input field in a checkbox. Useful for form submission. + * The name of the input field in a checkbox. + * Useful for form submission. */ name?: string /** @@ -120,19 +125,19 @@ export interface MachineApi { /** * Whether the checkbox is checked */ - isChecked: boolean + checked: boolean /** * Whether the checkbox is disabled */ - isDisabled: boolean | undefined + disabled: boolean | undefined /** * Whether the checkbox is indeterminate */ - isIndeterminate: boolean + indeterminate: boolean /** * Whether the checkbox is focused */ - isFocused: boolean | undefined + focused: boolean | undefined /** * The checked state of the checkbox */ diff --git a/packages/machines/clipboard/src/clipboard.connect.ts b/packages/machines/clipboard/src/clipboard.connect.ts index ed630cec6e..db267e5c61 100644 --- a/packages/machines/clipboard/src/clipboard.connect.ts +++ b/packages/machines/clipboard/src/clipboard.connect.ts @@ -5,10 +5,10 @@ import type { MachineApi, Send, State } from "./clipboard.types" import { dom } from "./clipboard.dom" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { - const isCopied = state.matches("copied") + const copied = state.matches("copied") return { - isCopied, + copied, value: state.context.value, setValue(value) { send({ type: "VALUE.SET", value }) @@ -18,23 +18,23 @@ export function connect(state: State, send: Send, normalize }, rootProps: normalize.element({ ...parts.root.attrs, - "data-copied": dataAttr(isCopied), + "data-copied": dataAttr(copied), id: dom.getRootId(state.context), }), labelProps: normalize.label({ ...parts.label.attrs, htmlFor: dom.getInputId(state.context), - "data-copied": dataAttr(isCopied), + "data-copied": dataAttr(copied), id: dom.getLabelId(state.context), }), controlProps: normalize.element({ ...parts.control.attrs, - "data-copied": dataAttr(isCopied), + "data-copied": dataAttr(copied), }), inputProps: normalize.input({ ...parts.input.attrs, defaultValue: state.context.value, - "data-copied": dataAttr(isCopied), + "data-copied": dataAttr(copied), readOnly: true, "data-readonly": "true", id: dom.getInputId(state.context), @@ -47,8 +47,8 @@ export function connect(state: State, send: Send, normalize }), triggerProps: normalize.button({ ...parts.trigger.attrs, - "aria-label": isCopied ? "Copied to clipboard" : "Copy to clipboard", - "data-copied": dataAttr(isCopied), + "aria-label": copied ? "Copied to clipboard" : "Copy to clipboard", + "data-copied": dataAttr(copied), onClick() { send({ type: "COPY" }) }, @@ -56,7 +56,7 @@ export function connect(state: State, send: Send, normalize getIndicatorProps(props) { return normalize.element({ ...parts.indicator.attrs, - hidden: props.copied !== isCopied, + hidden: props.copied !== copied, }) }, } diff --git a/packages/machines/clipboard/src/clipboard.types.ts b/packages/machines/clipboard/src/clipboard.types.ts index 89fb00c7c0..ad5c700061 100644 --- a/packages/machines/clipboard/src/clipboard.types.ts +++ b/packages/machines/clipboard/src/clipboard.types.ts @@ -58,7 +58,7 @@ export interface MachineApi { /** * Whether the value has been copied to the clipboard */ - isCopied: boolean + copied: boolean /** * The value to be copied to the clipboard */ diff --git a/packages/machines/collapsible/src/collapsible.connect.ts b/packages/machines/collapsible/src/collapsible.connect.ts index 7d2fcfd25d..7034c3daf5 100644 --- a/packages/machines/collapsible/src/collapsible.connect.ts +++ b/packages/machines/collapsible/src/collapsible.connect.ts @@ -5,39 +5,37 @@ import { dom } from "./collapsible.dom" import type { MachineApi, Send, State } from "./collapsible.types" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { - const isVisible = state.matches("open", "closing") - const isOpen = state.matches("open") + const visible = state.matches("open", "closing") + const open = state.matches("open") const height = state.context.height const width = state.context.width - const isDisabled = !!state.context.disabled + const disabled = !!state.context.disabled - const skipMountAnimation = state.context.isMountAnimationPrevented && isOpen + const skipMountAnimation = state.context.isMountAnimationPrevented && open return { - isDisabled, - isVisible, - isOpen, - open() { - send("OPEN") - }, - close() { - send("CLOSE") + disabled, + visible, + open, + setOpen(_open) { + if (_open === open) return + send(_open ? "OPEN" : "CLOSE") }, rootProps: normalize.element({ ...parts.root.attrs, - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", dir: state.context.dir, id: dom.getRootId(state.context), }), contentProps: normalize.element({ ...parts.content.attrs, - "data-state": skipMountAnimation ? undefined : isOpen ? "open" : "closed", + "data-state": skipMountAnimation ? undefined : open ? "open" : "closed", id: dom.getContentId(state.context), - "data-disabled": dataAttr(isDisabled), - hidden: !isVisible, + "data-disabled": dataAttr(disabled), + hidden: !visible, style: { "--height": height != null ? `${height}px` : undefined, "--width": width != null ? `${width}px` : undefined, @@ -49,13 +47,13 @@ export function connect(state: State, send: Send, normalize id: dom.getTriggerId(state.context), dir: state.context.dir, type: "button", - "data-state": isOpen ? "open" : "closed", - "data-disabled": dataAttr(isDisabled), + "data-state": open ? "open" : "closed", + "data-disabled": dataAttr(disabled), "aria-controls": dom.getContentId(state.context), - "aria-expanded": isVisible || false, + "aria-expanded": visible || false, onClick() { - if (isDisabled) return - send({ type: isOpen ? "CLOSE" : "OPEN", src: "trigger.click" }) + if (disabled) return + send({ type: open ? "CLOSE" : "OPEN", src: "trigger.click" }) }, }), } diff --git a/packages/machines/collapsible/src/collapsible.types.ts b/packages/machines/collapsible/src/collapsible.types.ts index 1534bcd502..a203963455 100644 --- a/packages/machines/collapsible/src/collapsible.types.ts +++ b/packages/machines/collapsible/src/collapsible.types.ts @@ -91,23 +91,20 @@ export interface MachineApi { /** * Whether the collapsible is open. */ - isOpen: boolean + open: boolean /** * Whether the collapsible is visible (open or closing) */ - isVisible: boolean + visible: boolean /** * Whether the collapsible is disabled */ - isDisabled: boolean - /** - * Function to open the collapsible. - */ - open(): void + disabled: boolean /** - * Function to close the collapsible. + * Function to open or close the collapsible. */ - close(): void + setOpen(open: boolean): void + rootProps: T["element"] triggerProps: T["button"] contentProps: T["element"] diff --git a/packages/machines/color-picker/package.json b/packages/machines/color-picker/package.json index d7a2811237..8905765bcc 100644 --- a/packages/machines/color-picker/package.json +++ b/packages/machines/color-picker/package.json @@ -44,7 +44,6 @@ "@zag-js/utils": "workspace:*", "@zag-js/form-utils": "workspace:*", "@zag-js/color-utils": "workspace:*", - "@zag-js/visually-hidden": "workspace:*", "@zag-js/popper": "workspace:*", "@zag-js/text-selection": "workspace:*", "@zag-js/types": "workspace:*" diff --git a/packages/machines/color-picker/src/color-picker.connect.ts b/packages/machines/color-picker/src/color-picker.connect.ts index f284442c8b..ad4988e790 100644 --- a/packages/machines/color-picker/src/color-picker.connect.ts +++ b/packages/machines/color-picker/src/color-picker.connect.ts @@ -8,10 +8,9 @@ import { isModifierKey, type EventKeyMap, } from "@zag-js/dom-event" -import { dataAttr, query } from "@zag-js/dom-query" +import { dataAttr, query, visuallyHiddenStyle } from "@zag-js/dom-query" import { getPlacementStyles } from "@zag-js/popper" import type { NormalizeProps, PropTypes } from "@zag-js/types" -import { visuallyHiddenStyle } from "@zag-js/visually-hidden" import { parts } from "./color-picker.anatomy" import { dom } from "./color-picker.dom" import type { @@ -32,12 +31,12 @@ export function connect(state: State, send: Send, normalize const areaValue = state.context.areaValue const valueAsString = state.context.valueAsString - const isDisabled = state.context.isDisabled - const isInteractive = state.context.isInteractive + const disabled = state.context.isDisabled + const interactive = state.context.isInteractive - const isDragging = state.hasTag("dragging") - const isOpen = state.hasTag("open") - const isFocused = state.hasTag("focused") + const dragging = state.hasTag("dragging") + const open = state.hasTag("open") + const focused = state.hasTag("focused") const getAreaChannels = (props: AreaProps) => { const channels = areaValue.getChannels() @@ -58,21 +57,19 @@ export function connect(state: State, send: Send, normalize return { value: color, valueAsString: color.toString("hex"), - isChecked: color.isEqual(value), - isDisabled: props.disabled || !isInteractive, + checked: color.isEqual(value), + disabled: props.disabled || !interactive, } } return { - isDragging, - isOpen, + dragging, + open, valueAsString, value, - open() { - send({ type: "OPEN" }) - }, - close() { - send({ type: "CLOSE" }) + setOpen(_open) { + if (_open === open) return + send({ type: _open ? "OPEN" : "CLOSE" }) }, setValue(value) { send({ type: "VALUE.SET", value: normalizeColor(value), src: "set-color" }) @@ -99,7 +96,7 @@ export function connect(state: State, send: Send, normalize ...parts.root.attrs, dir: state.context.dir, id: dom.getRootId(state.context), - "data-disabled": dataAttr(isDisabled), + "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(state.context.readOnly), style: { "--value": value.toString("css"), @@ -111,9 +108,9 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, id: dom.getLabelId(state.context), htmlFor: dom.getHiddenInputId(state.context), - "data-disabled": dataAttr(isDisabled), + "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(state.context.readOnly), - "data-focus": dataAttr(isFocused), + "data-focus": dataAttr(focused), onClick(event) { event.preventDefault() const inputEl = query(dom.getControlEl(state.context), "[data-channel=hex]") @@ -125,33 +122,33 @@ export function connect(state: State, send: Send, normalize ...parts.control.attrs, id: dom.getControlId(state.context), dir: state.context.dir, - "data-disabled": dataAttr(isDisabled), + "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(state.context.readOnly), - "data-state": isOpen ? "open" : "closed", - "data-focus": dataAttr(isFocused), + "data-state": open ? "open" : "closed", + "data-focus": dataAttr(focused), }), triggerProps: normalize.button({ ...parts.trigger.attrs, id: dom.getTriggerId(state.context), dir: state.context.dir, - disabled: isDisabled, + disabled: disabled, "aria-label": `select color. current color is ${valueAsString}`, "aria-controls": dom.getContentId(state.context), "aria-labelledby": dom.getLabelId(state.context), - "data-disabled": dataAttr(isDisabled), + "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(state.context.readOnly), "data-placement": currentPlacement, - "aria-expanded": dataAttr(isOpen), - "data-state": isOpen ? "open" : "closed", - "data-focus": dataAttr(isFocused), + "aria-expanded": dataAttr(open), + "data-state": open ? "open" : "closed", + "data-focus": dataAttr(focused), type: "button", onClick() { - if (!isInteractive) return + if (!interactive) return send({ type: "TRIGGER.CLICK" }) }, onBlur() { - if (!isInteractive) return + if (!interactive) return send({ type: "TRIGGER.BLUR" }) }, style: { @@ -171,8 +168,8 @@ export function connect(state: State, send: Send, normalize id: dom.getContentId(state.context), dir: state.context.dir, "data-placement": currentPlacement, - "data-state": isOpen ? "open" : "closed", - hidden: !isOpen, + "data-state": open ? "open" : "closed", + hidden: !open, }), getAreaProps(props = {}) { @@ -188,7 +185,7 @@ export function connect(state: State, send: Send, normalize id: dom.getAreaId(state.context), role: "group", onPointerDown(event) { - if (!isInteractive) return + if (!interactive) return const evt = getNativeEvent(event) if (!isLeftClick(evt) || isModifierKey(evt)) return @@ -242,8 +239,8 @@ export function connect(state: State, send: Send, normalize ...parts.areaThumb.attrs, id: dom.getAreaThumbId(state.context), dir: state.context.dir, - tabIndex: isDisabled ? undefined : 0, - "data-disabled": dataAttr(isDisabled), + tabIndex: disabled ? undefined : 0, + "data-disabled": dataAttr(disabled), role: "slider", "aria-valuemin": 0, "aria-valuemax": 100, @@ -261,12 +258,12 @@ export function connect(state: State, send: Send, normalize background: areaValue.withChannelValue("alpha", 1).toString("css"), }, onFocus() { - if (!isInteractive) return + if (!interactive) return send({ type: "AREA.FOCUS", id: "area", channel }) }, onKeyDown(event) { if (event.defaultPrevented) return - if (!isInteractive) return + if (!interactive) return const step = getEventStep(event) @@ -331,7 +328,7 @@ export function connect(state: State, send: Send, normalize "data-orientation": orientation, role: "presentation", onPointerDown(event) { - if (!isInteractive) return + if (!interactive) return const evt = getNativeEvent(event) if (!isLeftClick(evt) || isModifierKey(evt)) return @@ -387,11 +384,11 @@ export function connect(state: State, send: Send, normalize id: dom.getChannelSliderThumbId(state.context, channel), role: "slider", "aria-label": channel, - tabIndex: isDisabled ? undefined : 0, + tabIndex: disabled ? undefined : 0, "data-channel": channel, - "data-disabled": dataAttr(isDisabled), + "data-disabled": dataAttr(disabled), "data-orientation": orientation, - "aria-disabled": dataAttr(isDisabled), + "aria-disabled": dataAttr(disabled), "aria-orientation": orientation, "aria-valuemax": maxValue, "aria-valuemin": minValue, @@ -404,12 +401,12 @@ export function connect(state: State, send: Send, normalize ...placementStyles, }, onFocus() { - if (!isInteractive) return + if (!interactive) return send({ type: "CHANNEL_SLIDER.FOCUS", channel }) }, onKeyDown(event) { if (event.defaultPrevented) return - if (!isInteractive) return + if (!interactive) return const step = getEventStep(event) * stepValue @@ -466,33 +463,33 @@ export function connect(state: State, send: Send, normalize "aria-label": channel, spellCheck: false, autoComplete: "off", - disabled: isDisabled, - "data-disabled": dataAttr(isDisabled), + disabled: disabled, + "data-disabled": dataAttr(disabled), readOnly: state.context.readOnly, defaultValue: getChannelValue(value, channel), min: range?.minValue, max: range?.maxValue, step: range?.step, onBeforeInput(event) { - if (isTextField || !isInteractive) return + if (isTextField || !interactive) return const value = event.currentTarget.value if (value.match(/[^0-9.]/g)) { event.preventDefault() } }, onFocus(event) { - if (!isInteractive) return + if (!interactive) return send({ type: "CHANNEL_INPUT.FOCUS", channel }) event.target.select() }, onBlur(event) { - if (!isInteractive) return + if (!interactive) return const value = isTextField ? event.currentTarget.value : event.currentTarget.valueAsNumber send({ type: "CHANNEL_INPUT.BLUR", channel, value, isTextField }) }, onKeyDown(event) { if (event.defaultPrevented) return - if (!isInteractive) return + if (!interactive) return if (event.key === "Enter") { const value = isTextField ? event.currentTarget.value : event.currentTarget.valueAsNumber send({ type: "CHANNEL_INPUT.CHANGE", channel, value, isTextField }) @@ -509,7 +506,7 @@ export function connect(state: State, send: Send, normalize hiddenInputProps: normalize.input({ type: "text", - disabled: isDisabled, + disabled: disabled, name: state.context.name, id: dom.getHiddenInputId(state.context), style: visuallyHiddenStyle, @@ -520,11 +517,11 @@ export function connect(state: State, send: Send, normalize ...parts.eyeDropperTrigger.attrs, type: "button", dir: state.context.dir, - disabled: isDisabled, - "data-disabled": dataAttr(isDisabled), + disabled: disabled, + "data-disabled": dataAttr(disabled), "aria-label": "Pick a color from the screen", onClick() { - if (!isInteractive) return + if (!interactive) return send("EYEDROPPER.CLICK") }, }), @@ -540,15 +537,15 @@ export function connect(state: State, send: Send, normalize const triggerState = getSwatchTriggerState(props) return normalize.button({ ...parts.swatchTrigger.attrs, - disabled: triggerState.isDisabled, + disabled: triggerState.disabled, dir: state.context.dir, type: "button", "aria-label": `select ${triggerState.valueAsString} as the color`, - "data-state": triggerState.isChecked ? "checked" : "unchecked", + "data-state": triggerState.checked ? "checked" : "unchecked", "data-value": triggerState.valueAsString, - "data-disabled": dataAttr(triggerState.isDisabled), + "data-disabled": dataAttr(triggerState.disabled), onClick() { - if (triggerState.isDisabled) return + if (triggerState.disabled) return send({ type: "SWATCH_TRIGGER.CLICK", value: triggerState.value }) }, style: { @@ -562,7 +559,7 @@ export function connect(state: State, send: Send, normalize return normalize.element({ ...parts.swatchIndicator.attrs, dir: state.context.dir, - hidden: !triggerState.isChecked, + hidden: !triggerState.checked, }) }, @@ -572,7 +569,7 @@ export function connect(state: State, send: Send, normalize return normalize.element({ ...parts.swatch.attrs, dir: state.context.dir, - "data-state": triggerState.isChecked ? "checked" : "unchecked", + "data-state": triggerState.checked ? "checked" : "unchecked", "data-value": triggerState.valueAsString, style: { position: "relative", @@ -598,7 +595,7 @@ export function connect(state: State, send: Send, normalize "aria-label": "change color format", dir: state.context.dir, defaultValue: state.context.format, - disabled: isDisabled, + disabled: disabled, onChange(event) { const format = assertFormat(event.currentTarget.value) send({ type: "FORMAT.SET", format, src: "format-select" }) diff --git a/packages/machines/color-picker/src/color-picker.machine.ts b/packages/machines/color-picker/src/color-picker.machine.ts index b0a1d271fa..4bb0f1a20f 100644 --- a/packages/machines/color-picker/src/color-picker.machine.ts +++ b/packages/machines/color-picker/src/color-picker.machine.ts @@ -404,11 +404,11 @@ export function machine(userContext: UserDefinedContext) { openEyeDropper(ctx) { const isSupported = "EyeDropper" in dom.getWin(ctx) if (!isSupported) return - const win = dom.getWin(ctx) as any + const win = dom.getWin(ctx) const picker = new win.EyeDropper() picker .open() - .then(({ sRGBHex }: { sRGBHex: string }) => { + .then(({ sRGBHex }) => { const format = ctx.value.getFormat() const color = parseColor(sRGBHex).toFormat(format) as Color set.value(ctx, color) diff --git a/packages/machines/color-picker/src/color-picker.types.ts b/packages/machines/color-picker/src/color-picker.types.ts index d01e222427..c6dd65a700 100644 --- a/packages/machines/color-picker/src/color-picker.types.ts +++ b/packages/machines/color-picker/src/color-picker.types.ts @@ -7,6 +7,20 @@ import type { MaybeFunction } from "@zag-js/utils" export type ExtendedColorChannel = ColorChannel | "hex" | "css" +// patch the global window object to include the EyeDropper API + +interface EyeDropper { + new (): EyeDropper + open: (options?: { signal?: AbortSignal }) => Promise<{ sRGBHex: string }> + [Symbol.toStringTag]: "EyeDropper" +} + +declare global { + interface Window { + EyeDropper: EyeDropper + } +} + /* ----------------------------------------------------------------------------- * Callback details * -----------------------------------------------------------------------------*/ @@ -218,8 +232,8 @@ export interface SwatchTriggerProps { export interface SwatchTriggerState { value: Color valueAsString: string - isChecked: boolean - isDisabled: boolean + checked: boolean + disabled: boolean } export interface SwatchProps { @@ -241,11 +255,11 @@ export interface MachineApi { /** * Whether the color picker is being dragged */ - isDragging: boolean + dragging: boolean /** * Whether the color picker is open */ - isOpen: boolean + open: boolean /** * The current color value (as a string) */ @@ -283,13 +297,9 @@ export interface MachineApi { */ setAlpha(value: number): void /** - * Function to open the color picker - */ - open(): void - /** - * Function to close the color picker + * Function to open or close the color picker */ - close(): void + setOpen(open: boolean): void rootProps: T["element"] labelProps: T["element"] diff --git a/packages/machines/combobox/src/combobox.connect.ts b/packages/machines/combobox/src/combobox.connect.ts index c698c343e7..56bea6054a 100644 --- a/packages/machines/combobox/src/combobox.connect.ts +++ b/packages/machines/combobox/src/combobox.connect.ts @@ -11,7 +11,7 @@ import { getPlacementStyles } from "@zag-js/popper" import type { NormalizeProps, PropTypes } from "@zag-js/types" import { parts } from "./combobox.anatomy" import { dom } from "./combobox.dom" -import type { CollectionItem, ItemProps, MachineApi, Send, State } from "./combobox.types" +import type { CollectionItem, ItemProps, ItemState, MachineApi, Send, State } from "./combobox.types" export function connect( state: State, @@ -21,13 +21,13 @@ export function connect( const translations = state.context.translations const collection = state.context.collection - const isDisabled = state.context.disabled - const isInteractive = state.context.isInteractive - const isInvalid = state.context.invalid - const isReadOnly = state.context.readOnly + const disabled = state.context.disabled + const interactive = state.context.isInteractive + const invalid = state.context.invalid + const readOnly = state.context.readOnly - const isOpen = state.hasTag("open") - const isFocused = state.hasTag("focused") + const open = state.hasTag("open") + const focused = state.hasTag("focused") const isDialogPopup = state.context.popup === "dialog" const popperStyles = getPlacementStyles({ @@ -35,23 +35,23 @@ export function connect( placement: state.context.currentPlacement, }) - function getItemState(props: ItemProps) { + function getItemState(props: ItemProps): ItemState { const { item } = props const disabled = collection.isItemDisabled(item) const value = collection.itemToValue(item) return { value, - isDisabled: Boolean(disabled || isDisabled), - isHighlighted: state.context.highlightedValue === value, - isSelected: state.context.value.includes(value), + disabled: Boolean(disabled || disabled), + highlighted: state.context.highlightedValue === value, + selected: state.context.value.includes(value), } } return { - isFocused, - isOpen, + focused, + open, inputValue: state.context.inputValue, - isInputValueEmpty: state.context.isInputValueEmpty, + inputEmpty: state.context.isInputValueEmpty, highlightedValue: state.context.highlightedValue, highlightedItem: state.context.highlightedItem, value: state.context.value, @@ -87,21 +87,16 @@ export function connect( focus() { dom.getInputEl(state.context)?.focus() }, - open() { - if (isOpen) return - send("OPEN") + setOpen(_open) { + if (_open === open) return + send(_open ? "OPEN" : "CLOSE") }, - close() { - if (!isOpen) return - send("CLOSE") - }, - rootProps: normalize.element({ ...parts.root.attrs, dir: state.context.dir, id: dom.getRootId(state.context), - "data-invalid": dataAttr(isInvalid), - "data-readonly": dataAttr(isReadOnly), + "data-invalid": dataAttr(invalid), + "data-readonly": dataAttr(readOnly), }), labelProps: normalize.label({ @@ -109,10 +104,10 @@ export function connect( dir: state.context.dir, htmlFor: dom.getInputId(state.context), id: dom.getLabelId(state.context), - "data-readonly": dataAttr(isReadOnly), - "data-disabled": dataAttr(isDisabled), - "data-invalid": dataAttr(isInvalid), - "data-focus": dataAttr(isFocused), + "data-readonly": dataAttr(readOnly), + "data-disabled": dataAttr(disabled), + "data-invalid": dataAttr(invalid), + "data-focus": dataAttr(focused), onClick(event) { if (!isDialogPopup) return event.preventDefault() @@ -124,10 +119,10 @@ export function connect( ...parts.control.attrs, dir: state.context.dir, id: dom.getControlId(state.context), - "data-state": isOpen ? "open" : "closed", - "data-focus": dataAttr(isFocused), - "data-disabled": dataAttr(isDisabled), - "data-invalid": dataAttr(isInvalid), + "data-state": open ? "open" : "closed", + "data-focus": dataAttr(focused), + "data-disabled": dataAttr(disabled), + "data-invalid": dataAttr(invalid), }), positionerProps: normalize.element({ @@ -140,17 +135,17 @@ export function connect( inputProps: normalize.input({ ...parts.input.attrs, dir: state.context.dir, - "aria-invalid": ariaAttr(isInvalid), - "data-invalid": dataAttr(isInvalid), + "aria-invalid": ariaAttr(invalid), + "data-invalid": dataAttr(invalid), name: state.context.name, form: state.context.form, - disabled: isDisabled, + disabled: disabled, autoFocus: state.context.autoFocus, autoComplete: "off", autoCorrect: "off", autoCapitalize: "none", spellCheck: "false", - readOnly: isReadOnly, + readOnly: readOnly, placeholder: state.context.placeholder, id: dom.getInputId(state.context), type: "text", @@ -158,22 +153,22 @@ export function connect( defaultValue: state.context.inputValue, "aria-autocomplete": state.context.autoComplete ? "both" : "list", "aria-controls": isDialogPopup ? dom.getListId(state.context) : dom.getContentId(state.context), - "aria-expanded": isOpen, - "data-state": isOpen ? "open" : "closed", + "aria-expanded": open, + "data-state": open ? "open" : "closed", "aria-activedescendant": state.context.highlightedValue ? dom.getItemId(state.context, state.context.highlightedValue) : undefined, onClick() { if (!state.context.openOnClick) return - if (!isInteractive) return + if (!interactive) return send("INPUT.CLICK") }, onFocus() { - if (isDisabled) return + if (disabled) return send("INPUT.FOCUS") }, onBlur() { - if (isDisabled) return + if (disabled) return send("INPUT.BLUR") }, onChange(event) { @@ -181,7 +176,7 @@ export function connect( }, onKeyDown(event) { if (event.defaultPrevented) return - if (!isInteractive) return + if (!interactive) return const evt = getNativeEvent(event) if (evt.ctrlKey || evt.shiftKey || evt.isComposing) return @@ -192,33 +187,33 @@ export function connect( const keymap: EventKeyMap = { ArrowDown(event) { - if (!openOnKeyPress && !isOpen) return + if (!openOnKeyPress && !open) return send({ type: event.altKey ? "OPEN" : "INPUT.ARROW_DOWN", keypress }) event.preventDefault() }, ArrowUp() { - if (!openOnKeyPress && !isOpen) return + if (!openOnKeyPress && !open) return send({ type: event.altKey ? "CLOSE" : "INPUT.ARROW_UP", keypress }) event.preventDefault() }, Home(event) { if (isModifierKey) return send({ type: "INPUT.HOME", keypress }) - if (isOpen) { + if (open) { event.preventDefault() } }, End(event) { if (isModifierKey) return send({ type: "INPUT.END", keypress }) - if (isOpen) { + if (open) { event.preventDefault() } }, Enter(event) { if (evt.isComposing) return send({ type: "INPUT.ENTER", keypress }) - if (isOpen) { + if (open) { event.preventDefault() } const itemEl = dom.getHighlightedItemEl(state.context) @@ -244,20 +239,20 @@ export function connect( type: "button", tabIndex: isDialogPopup ? 0 : -1, "aria-label": translations.triggerLabel, - "aria-expanded": isOpen, - "data-state": isOpen ? "open" : "closed", - "aria-controls": isOpen ? dom.getContentId(state.context) : undefined, - disabled: isDisabled, - "data-readonly": dataAttr(isReadOnly), - "data-disabled": dataAttr(isDisabled), + "aria-expanded": open, + "data-state": open ? "open" : "closed", + "aria-controls": open ? dom.getContentId(state.context) : undefined, + disabled: disabled, + "data-readonly": dataAttr(readOnly), + "data-disabled": dataAttr(disabled), onClick(event) { const evt = getNativeEvent(event) - if (!isInteractive) return + if (!interactive) return if (!isLeftClick(evt)) return send("TRIGGER.CLICK") }, onPointerDown(event) { - if (!isInteractive) return + if (!interactive) return if (event.pointerType === "touch") return event.preventDefault() queueMicrotask(() => { @@ -301,8 +296,8 @@ export function connect( id: dom.getContentId(state.context), role: isDialogPopup ? "dialog" : "listbox", tabIndex: -1, - hidden: !isOpen, - "data-state": isOpen ? "open" : "closed", + hidden: !open, + "data-state": open ? "open" : "closed", "aria-labelledby": dom.getLabelId(state.context), "aria-multiselectable": state.context.multiple && !isDialogPopup ? true : undefined, onPointerDown(event) { @@ -324,12 +319,12 @@ export function connect( id: dom.getClearTriggerId(state.context), type: "button", tabIndex: -1, - disabled: isDisabled, + disabled: disabled, "aria-label": translations.clearTriggerLabel, "aria-controls": dom.getInputId(state.context), hidden: !state.context.value.length, onClick() { - if (!isInteractive) return + if (!interactive) return send({ type: "VALUE.CLEAR", src: "clear-trigger" }) }, }), @@ -346,19 +341,19 @@ export function connect( id: dom.getItemId(state.context, value), role: "option", tabIndex: -1, - "data-highlighted": dataAttr(itemState.isHighlighted), - "data-state": itemState.isSelected ? "checked" : "unchecked", - "aria-selected": itemState.isHighlighted, - "aria-disabled": itemState.isDisabled, - "data-disabled": dataAttr(itemState.isDisabled), + "data-highlighted": dataAttr(itemState.highlighted), + "data-state": itemState.selected ? "checked" : "unchecked", + "aria-selected": itemState.highlighted, + "aria-disabled": itemState.disabled, + "data-disabled": dataAttr(itemState.disabled), "data-value": itemState.value, onPointerMove() { - if (itemState.isDisabled) return + if (itemState.disabled) return send({ type: "ITEM.POINTER_MOVE", value }) }, onPointerLeave() { if (props.persistFocus) return - if (itemState.isDisabled) return + if (itemState.disabled) return const mouseMoved = state.previousEvent.type === "ITEM.POINTER_MOVE" if (!mouseMoved) return send({ type: "ITEM.POINTER_LEAVE", value }) @@ -367,7 +362,7 @@ export function connect( if (isDownloadingEvent(event)) return if (isOpeningInNewTab(event)) return if (isContextMenuEvent(event)) return - if (itemState.isDisabled) return + if (itemState.disabled) return send({ type: "ITEM.CLICK", src: "pointerup", value }) }, onTouchEnd(event) { @@ -383,8 +378,8 @@ export function connect( return normalize.element({ ...parts.itemText.attrs, dir: state.context.dir, - "data-disabled": dataAttr(itemState.isDisabled), - "data-highlighted": dataAttr(itemState.isHighlighted), + "data-disabled": dataAttr(itemState.disabled), + "data-highlighted": dataAttr(itemState.highlighted), }) }, getItemIndicatorProps(props) { @@ -393,8 +388,8 @@ export function connect( "aria-hidden": true, ...parts.itemIndicator.attrs, dir: state.context.dir, - "data-state": itemState.isSelected ? "checked" : "unchecked", - hidden: !itemState.isSelected, + "data-state": itemState.selected ? "checked" : "unchecked", + hidden: !itemState.selected, }) }, diff --git a/packages/machines/combobox/src/combobox.types.ts b/packages/machines/combobox/src/combobox.types.ts index 6bd495fac1..858b85e86c 100644 --- a/packages/machines/combobox/src/combobox.types.ts +++ b/packages/machines/combobox/src/combobox.types.ts @@ -278,15 +278,33 @@ export type Send = S.Send * -----------------------------------------------------------------------------*/ export interface ItemProps { + /** + * Whether hovering outside should clear the highlighted state + */ persistFocus?: boolean + /** + * The item to render + */ item: CollectionItem } export interface ItemState { + /** + * The value of the item + */ value: string - isDisabled: boolean - isSelected: boolean - isHighlighted: boolean + /** + * Whether the item is disabled + */ + disabled: boolean + /** + * Whether the item is selected + */ + selected: boolean + /** + * Whether the item is highlighted via pointer or keyboard navigation + */ + highlighted: boolean } export interface ItemGroupProps { @@ -301,15 +319,15 @@ export interface MachineApi(state: State, send: Send, normalize const disabled = state.context.disabled const readOnly = state.context.readOnly - const isInteractive = state.context.isInteractive + const interactive = state.context.isInteractive const min = state.context.min const max = state.context.max @@ -71,8 +71,8 @@ export function connect(state: State, send: Send, normalize const timeZone = state.context.timeZone const startOfWeek = state.context.startOfWeek - const isFocused = state.matches("focused") - const isOpen = state.matches("open") + const focused = state.matches("focused") + const open = state.matches("open") const isRangePicker = state.context.selectionMode === "range" const isDateUnavailableFn = state.context.isDateUnavailable @@ -120,12 +120,12 @@ export function connect(state: State, send: Send, normalize const { value, disabled } = props const normalized = focusedValue.set({ year: value }) const cellState = { - isFocused: focusedValue.year === props.value, - isSelectable: !isDateInvalid(normalized, min, max), - isSelected: !!selectedValue.find((date) => date.year === value), + focused: focusedValue.year === props.value, + selectable: !isDateInvalid(normalized, min, max), + selected: !!selectedValue.find((date) => date.year === value), valueText: value.toString(), - get isDisabled() { - return disabled || !cellState.isSelectable + get disabled() { + return disabled || !cellState.selectable }, } return cellState @@ -136,12 +136,12 @@ export function connect(state: State, send: Send, normalize const normalized = focusedValue.set({ month: value }) const formatter = getMonthFormatter(locale, timeZone) const cellState = { - isFocused: focusedValue.month === props.value, - isSelectable: !isDateInvalid(normalized, min, max), - isSelected: !!selectedValue.find((date) => date.month === value && date.year === focusedValue.year), + focused: focusedValue.month === props.value, + selectable: !isDateInvalid(normalized, min, max), + selected: !!selectedValue.find((date) => date.month === value && date.year === focusedValue.year), valueText: formatter.format(normalized.toDate(timeZone)), - get isDisabled() { - return disabled || !cellState.isSelectable + get disabled() { + return disabled || !cellState.selectable }, } return cellState @@ -156,28 +156,28 @@ export function connect(state: State, send: Send, normalize const end = visibleRange.start.add(unitDuration).subtract({ days: 1 }) const cellState = { - isInvalid: isDateInvalid(value, min, max), - isDisabled: disabled || isDateDisabled(value, visibleRange.start, end, min, max), - isSelected: selectedValue.some((date) => isDateEqual(value, date)), - isUnavailable: isDateUnavailable(value, isDateUnavailableFn, locale, min, max) && !disabled, - isOutsideRange: isDateOutsideVisibleRange(value, visibleRange.start, end), - isInRange: + invalid: isDateInvalid(value, min, max), + disabled: disabled || isDateDisabled(value, visibleRange.start, end, min, max), + selected: selectedValue.some((date) => isDateEqual(value, date)), + unavailable: isDateUnavailable(value, isDateUnavailableFn, locale, min, max) && !disabled, + outsideRange: isDateOutsideVisibleRange(value, visibleRange.start, end), + inRange: isRangePicker && (isDateWithinRange(value, selectedValue) || isDateWithinRange(value, hoveredRangeValue)), - isFirstInRange: isRangePicker && isDateEqual(value, selectedValue[0]), - isLastInRange: isRangePicker && isDateEqual(value, selectedValue[1]), - isToday: isTodayDate(value, timeZone), - isWeekend: isWeekend(value, locale), + firstInRange: isRangePicker && isDateEqual(value, selectedValue[0]), + lastInRange: isRangePicker && isDateEqual(value, selectedValue[1]), + today: isTodayDate(value, timeZone), + weekend: isWeekend(value, locale), formattedDate: formatter.format(value.toDate(timeZone)), - get isFocused() { - return isDateEqual(value, focusedValue) && !cellState.isOutsideRange + get focused() { + return isDateEqual(value, focusedValue) && !cellState.outsideRange }, get ariaLabel() { - if (cellState.isUnavailable) return `Not available. ${cellState.formattedDate}` - if (cellState.isSelected) return `Selected date. ${cellState.formattedDate}` + if (cellState.unavailable) return `Not available. ${cellState.formattedDate}` + if (cellState.selected) return `Selected date. ${cellState.formattedDate}` return `Choose ${cellState.formattedDate}` }, - get isSelectable() { - return !cellState.isDisabled && !cellState.isUnavailable + get selectable() { + return !cellState.disabled && !cellState.unavailable }, } return cellState @@ -189,8 +189,8 @@ export function connect(state: State, send: Send, normalize } return { - isFocused, - isOpen, + focused, + open, view: state.context.view, getRangePresetValue(preset) { return getDateRangePreset(preset, locale, timeZone) @@ -231,11 +231,9 @@ export function connect(state: State, send: Send, normalize setFocusedValue(value) { send({ type: "FOCUS.SET", value }) }, - open() { - send("OPEN") - }, - close() { - send("CLOSE") + setOpen(_open) { + if (_open === open) return + send(_open ? "OPEN" : "CLOSE") }, focusMonth, focusYear, @@ -270,7 +268,7 @@ export function connect(state: State, send: Send, normalize ...parts.root.attrs, dir: state.context.dir, id: dom.getRootId(state.context), - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(readOnly), }), @@ -279,7 +277,7 @@ export function connect(state: State, send: Send, normalize ...parts.label.attrs, dir: state.context.dir, htmlFor: dom.getInputId(state.context, 0), - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", "data-disabled": dataAttr(disabled), "data-readonly": dataAttr(readOnly), }), @@ -298,9 +296,9 @@ export function connect(state: State, send: Send, normalize contentProps: normalize.element({ ...parts.content.attrs, - hidden: !isOpen, + hidden: !open, dir: state.context.dir, - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", "data-placement": currentPlacement, id: dom.getContentId(state.context), role: "application", @@ -425,10 +423,10 @@ export function connect(state: State, send: Send, normalize return normalize.element({ ...parts.tableCell.attrs, role: "gridcell", - "aria-disabled": ariaAttr(!cellState.isSelectable), - "aria-selected": cellState.isSelected || cellState.isInRange, - "aria-invalid": ariaAttr(cellState.isInvalid), - "aria-current": cellState.isToday ? "date" : undefined, + "aria-disabled": ariaAttr(!cellState.selectable), + "aria-selected": cellState.selected || cellState.inRange, + "aria-invalid": ariaAttr(cellState.invalid), + "aria-current": cellState.today ? "date" : undefined, "data-value": value.toString(), }) }, @@ -440,28 +438,29 @@ export function connect(state: State, send: Send, normalize id: dom.getCellTriggerId(state.context, value.toString()), role: "button", dir: state.context.dir, - tabIndex: cellState.isFocused ? 0 : -1, + tabIndex: cellState.focused ? 0 : -1, "aria-label": cellState.ariaLabel, - "aria-disabled": ariaAttr(!cellState.isSelectable), - "aria-invalid": ariaAttr(cellState.isInvalid), - "data-disabled": dataAttr(!cellState.isSelectable), - "data-selected": dataAttr(cellState.isSelected), + "aria-disabled": ariaAttr(!cellState.selectable), + "aria-invalid": ariaAttr(cellState.invalid), + "data-disabled": dataAttr(!cellState.selectable), + "data-selected": dataAttr(cellState.selected), "data-value": value.toString(), "data-view": "day", - "data-today": dataAttr(cellState.isToday), - "data-focused": dataAttr(cellState.isFocused), - "data-unavailable": dataAttr(cellState.isUnavailable), - "data-range-start": dataAttr(cellState.isFirstInRange), - "data-range-end": dataAttr(cellState.isLastInRange), - "data-in-range": dataAttr(cellState.isInRange), - "data-outside-range": dataAttr(cellState.isOutsideRange), - "data-weekend": dataAttr(cellState.isWeekend), - onClick() { - if (!cellState.isSelectable) return + "data-today": dataAttr(cellState.today), + "data-focused": dataAttr(cellState.focused), + "data-unavailable": dataAttr(cellState.unavailable), + "data-range-start": dataAttr(cellState.firstInRange), + "data-range-end": dataAttr(cellState.lastInRange), + "data-in-range": dataAttr(cellState.inRange), + "data-outside-range": dataAttr(cellState.outsideRange), + "data-weekend": dataAttr(cellState.weekend), + onClick(event) { + if (event.defaultPrevented) return + if (!cellState.selectable) return send({ type: "CELL.CLICK", cell: "day", value }) }, onPointerMove(event) { - if (event.pointerType === "touch" || !cellState.isSelectable) return + if (event.pointerType === "touch" || !cellState.selectable) return const focus = event.currentTarget.ownerDocument.activeElement !== event.currentTarget if (hoveredValue && isEqualDay(value, hoveredValue)) return send({ type: "CELL.POINTER_MOVE", cell: "day", value, focus }) @@ -478,9 +477,9 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, colSpan: columns, role: "gridcell", - "aria-selected": ariaAttr(cellState.isSelected), - "data-selected": dataAttr(cellState.isSelected), - "aria-disabled": ariaAttr(!cellState.isSelectable), + "aria-selected": ariaAttr(cellState.selected), + "data-selected": dataAttr(cellState.selected), + "aria-disabled": ariaAttr(!cellState.selectable), "data-value": value, }) }, @@ -492,16 +491,17 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, role: "button", id: dom.getCellTriggerId(state.context, value.toString()), - "data-selected": dataAttr(cellState.isSelected), - "aria-disabled": ariaAttr(!cellState.isSelectable), - "data-disabled": dataAttr(!cellState.isSelectable), - "data-focused": dataAttr(cellState.isFocused), + "data-selected": dataAttr(cellState.selected), + "aria-disabled": ariaAttr(!cellState.selectable), + "data-disabled": dataAttr(!cellState.selectable), + "data-focused": dataAttr(cellState.focused), "aria-label": cellState.valueText, "data-view": "month", "data-value": value, - tabIndex: cellState.isFocused ? 0 : -1, - onClick() { - if (!cellState.isSelectable) return + tabIndex: cellState.focused ? 0 : -1, + onClick(event) { + if (event.defaultPrevented) return + if (!cellState.selectable) return send({ type: "CELL.CLICK", cell: "month", value }) }, }) @@ -516,9 +516,9 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, colSpan: columns, role: "gridcell", - "aria-selected": ariaAttr(cellState.isSelected), - "data-selected": dataAttr(cellState.isSelected), - "aria-disabled": ariaAttr(!cellState.isSelectable), + "aria-selected": ariaAttr(cellState.selected), + "data-selected": dataAttr(cellState.selected), + "aria-disabled": ariaAttr(!cellState.selectable), "data-value": value, }) }, @@ -530,16 +530,17 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, role: "button", id: dom.getCellTriggerId(state.context, value.toString()), - "data-selected": dataAttr(cellState.isSelected), - "data-focused": dataAttr(cellState.isFocused), - "aria-disabled": ariaAttr(!cellState.isSelectable), - "data-disabled": dataAttr(!cellState.isSelectable), + "data-selected": dataAttr(cellState.selected), + "data-focused": dataAttr(cellState.focused), + "aria-disabled": ariaAttr(!cellState.selectable), + "data-disabled": dataAttr(!cellState.selectable), "aria-label": cellState.valueText, "data-value": value, "data-view": "year", - tabIndex: cellState.isFocused ? 0 : -1, - onClick() { - if (!cellState.isSelectable) return + tabIndex: cellState.focused ? 0 : -1, + onClick(event) { + if (event.defaultPrevented) return + if (!cellState.selectable) return send({ type: "CELL.CLICK", cell: "year", value }) }, }) @@ -554,7 +555,8 @@ export function connect(state: State, send: Send, normalize type: "button", "aria-label": getNextTriggerLabel(view), disabled: disabled || !state.context.isNextVisibleRangeValid, - onClick() { + onClick(event) { + if (event.defaultPrevented) return send({ type: "GOTO.NEXT", view }) }, }) @@ -569,7 +571,8 @@ export function connect(state: State, send: Send, normalize type: "button", "aria-label": getPrevTriggerLabel(view), disabled: disabled || !state.context.isPrevVisibleRangeValid, - onClick() { + onClick(event) { + if (event.defaultPrevented) return send({ type: "GOTO.PREV", view }) }, }) @@ -582,7 +585,8 @@ export function connect(state: State, send: Send, normalize type: "button", "aria-label": "Clear dates", hidden: !state.context.value.length, - onClick() { + onClick(event) { + if (event.defaultPrevented) return send("VALUE.CLEAR") }, }), @@ -593,13 +597,14 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, type: "button", "data-placement": currentPlacement, - "aria-label": isOpen ? "Close calendar" : "Open calendar", + "aria-label": open ? "Close calendar" : "Open calendar", "aria-controls": dom.getContentId(state.context), - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", "aria-haspopup": "grid", disabled, - onClick() { - if (!isInteractive) return + onClick(event) { + if (event.defaultPrevented) return + if (!interactive) return send("TRIGGER.CLICK") }, }), @@ -614,8 +619,9 @@ export function connect(state: State, send: Send, normalize type: "button", disabled, "aria-label": getViewTriggerLabel(state.context.view), - onClick() { - if (!isInteractive) return + onClick(event) { + if (event.defaultPrevented) return + if (!interactive) return send("VIEW.CHANGE") }, }) @@ -641,7 +647,7 @@ export function connect(state: State, send: Send, normalize spellCheck: "false", dir: state.context.dir, name: state.context.name, - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", readOnly, disabled, placeholder: getInputPlaceholder(locale), @@ -660,7 +666,7 @@ export function connect(state: State, send: Send, normalize }, onKeyDown(event) { if (event.defaultPrevented) return - if (!isInteractive) return + if (!interactive) return const evt = getNativeEvent(event) if (evt.isComposing) return if (event.key !== "Enter") return @@ -714,7 +720,8 @@ export function connect(state: State, send: Send, normalize ? `select ${value[0].toString()} to ${value[1].toString()}` : `select ${value}`, type: "button", - onClick() { + onClick(event) { + if (event.defaultPrevented) return send({ type: "PRESET.CLICK", value }) }, }) diff --git a/packages/machines/date-picker/src/date-picker.types.ts b/packages/machines/date-picker/src/date-picker.types.ts index 1a8c502a61..d816ab6d36 100644 --- a/packages/machines/date-picker/src/date-picker.types.ts +++ b/packages/machines/date-picker/src/date-picker.types.ts @@ -317,11 +317,11 @@ export interface TableCellProps { } export interface TableCellState { - isFocused: boolean - isSelectable: boolean - isSelected: boolean + focused: boolean + selectable: boolean + selected: boolean valueText: string - readonly isDisabled: boolean + readonly disabled: boolean } export interface DayTableCellProps { @@ -331,20 +331,20 @@ export interface DayTableCellProps { } export interface DayTableCellState { - isInvalid: boolean - isDisabled: boolean - isSelected: boolean - isUnavailable: boolean - isOutsideRange: boolean - isInRange: boolean - isFirstInRange: boolean - isLastInRange: boolean - isToday: boolean - isWeekend: boolean + invalid: boolean + disabled: boolean + selected: boolean + unavailable: boolean + outsideRange: boolean + inRange: boolean + firstInRange: boolean + lastInRange: boolean + today: boolean + weekend: boolean formattedDate: string - readonly isFocused: boolean + readonly focused: boolean readonly ariaLabel: string - readonly isSelectable: boolean + readonly selectable: boolean } export interface TableProps { @@ -402,11 +402,11 @@ export interface MachineApi { /** * Whether the input is focused */ - isFocused: boolean + focused: boolean /** * Whether the date picker is open */ - isOpen: boolean + open: boolean /** * The current view of the date picker */ @@ -488,13 +488,9 @@ export interface MachineApi { */ clearValue(): void /** - * Function to open the calendar. - */ - open(): void - /** - * Function to close the calendar. + * Function to open or close the calendar. */ - close(): void + setOpen(open: boolean): void /** * Function to set the selected month. */ diff --git a/packages/machines/dialog/src/dialog.connect.ts b/packages/machines/dialog/src/dialog.connect.ts index 9debea931b..1aa91cf736 100644 --- a/packages/machines/dialog/src/dialog.connect.ts +++ b/packages/machines/dialog/src/dialog.connect.ts @@ -5,16 +5,14 @@ import type { MachineApi, Send, State } from "./dialog.types" export function connect(state: State, send: Send, normalize: NormalizeProps): MachineApi { const ariaLabel = state.context["aria-label"] - const isOpen = state.matches("open") + const open = state.matches("open") const rendered = state.context.renderedElements return { - isOpen, - open() { - send("OPEN") - }, - close() { - send("CLOSE") + open, + setOpen(_open) { + if (_open === open) return + send(_open ? "OPEN" : "CLOSE") }, triggerProps: normalize.button({ @@ -23,10 +21,11 @@ export function connect(state: State, send: Send, normalize id: dom.getTriggerId(state.context), "aria-haspopup": "dialog", type: "button", - "aria-expanded": isOpen, - "data-state": isOpen ? "open" : "closed", + "aria-expanded": open, + "data-state": open ? "open" : "closed", "aria-controls": dom.getContentId(state.context), - onClick() { + onClick(event) { + if (event.defaultPrevented) return send("TOGGLE") }, }), @@ -34,9 +33,9 @@ export function connect(state: State, send: Send, normalize backdropProps: normalize.element({ ...parts.backdrop.attrs, dir: state.context.dir, - hidden: !isOpen, + hidden: !open, id: dom.getBackdropId(state.context), - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", }), positionerProps: normalize.element({ @@ -44,7 +43,7 @@ export function connect(state: State, send: Send, normalize dir: state.context.dir, id: dom.getPositionerId(state.context), style: { - pointerEvents: isOpen ? undefined : "none", + pointerEvents: open ? undefined : "none", }, }), @@ -52,10 +51,10 @@ export function connect(state: State, send: Send, normalize ...parts.content.attrs, dir: state.context.dir, role: state.context.role, - hidden: !isOpen, + hidden: !open, id: dom.getContentId(state.context), tabIndex: -1, - "data-state": isOpen ? "open" : "closed", + "data-state": open ? "open" : "closed", "aria-modal": true, "aria-label": ariaLabel || undefined, "aria-labelledby": ariaLabel || !rendered.title ? undefined : dom.getTitleId(state.context), @@ -80,6 +79,7 @@ export function connect(state: State, send: Send, normalize id: dom.getCloseTriggerId(state.context), type: "button", onClick(event) { + if (event.defaultPrevented) return event.stopPropagation() send("CLOSE") }, diff --git a/packages/machines/dialog/src/dialog.types.ts b/packages/machines/dialog/src/dialog.types.ts index afbe63ba6e..47b30de38f 100644 --- a/packages/machines/dialog/src/dialog.types.ts +++ b/packages/machines/dialog/src/dialog.types.ts @@ -121,15 +121,11 @@ export interface MachineApi { /** * Whether the dialog is open */ - isOpen: boolean - /** - * Function to open the dialog - */ - open(): void + open: boolean /** - * Function to close the dialog + * Function to open or close the dialog */ - close(): void + setOpen(open: boolean): void triggerProps: T["button"] backdropProps: T["element"] diff --git a/packages/machines/editable/src/editable.connect.ts b/packages/machines/editable/src/editable.connect.ts index 51fb7544fa..8df6febf9d 100644 --- a/packages/machines/editable/src/editable.connect.ts +++ b/packages/machines/editable/src/editable.connect.ts @@ -6,24 +6,24 @@ import { dom } from "./editable.dom" import type { MachineApi, Send, State } from "./editable.types" export function connect
{api.type === "loading" && } {api.title} @@ -47,7 +34,7 @@ const ToastItem = defineComponent({ - +