Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/rude-seals-cover.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@zag-js/vanilla": patch
---

- Fix issue where vanilla machines do not have the option to change their props during runtime.
- Fix issue where some `aria-` attributes were toggled as boolean attributes and not as attributes with value strings.
10 changes: 10 additions & 0 deletions .changeset/scroll-area-overflow-css-vars.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"@zag-js/scroll-area": minor
---

Add overflow CSS variables to the viewport element for creating scroll fade effects:

- `--scroll-area-overflow-x-start`: Distance from horizontal start edge in pixels
- `--scroll-area-overflow-x-end`: Distance from horizontal end edge in pixels
- `--scroll-area-overflow-y-start`: Distance from vertical start edge in pixels
- `--scroll-area-overflow-y-end`: Distance from vertical end edge in pixels
10 changes: 5 additions & 5 deletions examples/vanilla-ts/src/accordion.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as accordion from "@zag-js/accordion"
import { normalizeProps, spreadProps, VanillaMachine } from "@zag-js/vanilla"
import { normalizeProps, VanillaMachine } from "@zag-js/vanilla"
import { Component } from "./component"

export class Accordion extends Component<accordion.Props, accordion.Api> {
Expand All @@ -12,7 +12,7 @@ export class Accordion extends Component<accordion.Props, accordion.Api> {
}

render = () => {
spreadProps(this.rootEl, this.api.getRootProps())
this.spreadProps(this.rootEl, this.api.getRootProps())
this.items.forEach((itemEl) => {
this.renderItem(itemEl)
})
Expand All @@ -29,8 +29,8 @@ export class Accordion extends Component<accordion.Props, accordion.Api> {
const itemContentEl = itemEl.querySelector<HTMLElement>(".accordion-content")
if (!itemTriggerEl) throw new Error("Expected triggerEl to be defined")
if (!itemContentEl) throw new Error("Expected contentEl to be defined")
spreadProps(itemEl, this.api.getItemProps({ value }))
spreadProps(itemTriggerEl, this.api.getItemTriggerProps({ value }))
spreadProps(itemContentEl, this.api.getItemContentProps({ value }))
this.spreadProps(itemEl, this.api.getItemProps({ value }))
this.spreadProps(itemTriggerEl, this.api.getItemTriggerProps({ value }))
this.spreadProps(itemContentEl, this.api.getItemContentProps({ value }))
}
}
18 changes: 9 additions & 9 deletions examples/vanilla-ts/src/angle-slider.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as angleSlider from "@zag-js/angle-slider"
import { Component } from "./component"
import { normalizeProps, spreadProps, VanillaMachine } from "@zag-js/vanilla"
import { normalizeProps, VanillaMachine } from "@zag-js/vanilla"

export class AngleSlider extends Component<angleSlider.Props, angleSlider.Api> {
initMachine(props: angleSlider.Props) {
Expand Down Expand Up @@ -36,33 +36,33 @@ export class AngleSlider extends Component<angleSlider.Props, angleSlider.Api> {
markerGroup.appendChild(markerEl)
}

spreadProps(markerEl, this.api.getMarkerProps({ value }))
this.spreadProps(markerEl, this.api.getMarkerProps({ value }))
})
}

render() {
spreadProps(this.rootEl, this.api.getRootProps())
this.spreadProps(this.rootEl, this.api.getRootProps())

const label = this.rootEl.querySelector<HTMLElement>(".angle-slider-label")
if (label) spreadProps(label, this.api.getLabelProps())
if (label) this.spreadProps(label, this.api.getLabelProps())

const valueText = this.rootEl.querySelector<HTMLElement>(".angle-slider-value-text")
if (valueText) {
spreadProps(valueText, this.api.getValueTextProps())
this.spreadProps(valueText, this.api.getValueTextProps())
valueText.textContent = this.api.valueAsDegree
}

const control = this.rootEl.querySelector<HTMLElement>(".angle-slider-control")
if (control) spreadProps(control, this.api.getControlProps())
if (control) this.spreadProps(control, this.api.getControlProps())

const thumb = this.rootEl.querySelector<HTMLElement>(".angle-slider-thumb")
if (thumb) spreadProps(thumb, this.api.getThumbProps())
if (thumb) this.spreadProps(thumb, this.api.getThumbProps())

const markerGroup = this.rootEl.querySelector<HTMLElement>(".angle-slider-marker-group")
if (markerGroup) spreadProps(markerGroup, this.api.getMarkerGroupProps())
if (markerGroup) this.spreadProps(markerGroup, this.api.getMarkerGroupProps())

const hiddenInput = this.rootEl.querySelector<HTMLInputElement>(".angle-slider-hidden-input")
if (hiddenInput) spreadProps(hiddenInput, this.api.getHiddenInputProps())
if (hiddenInput) this.spreadProps(hiddenInput, this.api.getHiddenInputProps())

// Sync markers
this.syncMarkers()
Expand Down
8 changes: 4 additions & 4 deletions examples/vanilla-ts/src/avatar.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as avatar from "@zag-js/avatar"
import { normalizeProps, spreadProps, VanillaMachine } from "@zag-js/vanilla"
import { normalizeProps, VanillaMachine } from "@zag-js/vanilla"
import { Component } from "./component"

export class Avatar extends Component<avatar.Props, avatar.Api> {
Expand All @@ -13,10 +13,10 @@ export class Avatar extends Component<avatar.Props, avatar.Api> {

render = () => {
const rootEl = this.rootEl
spreadProps(this.rootEl, this.api.getRootProps())
this.spreadProps(this.rootEl, this.api.getRootProps())
const imageEl = rootEl.querySelector<HTMLElement>(".avatar-image")
if (imageEl) spreadProps(imageEl, this.api.getImageProps())
if (imageEl) this.spreadProps(imageEl, this.api.getImageProps())
const fallbackEl = rootEl.querySelector<HTMLElement>(".avatar-fallback")
if (fallbackEl) spreadProps(fallbackEl, this.api.getFallbackProps())
if (fallbackEl) this.spreadProps(fallbackEl, this.api.getFallbackProps())
}
}
20 changes: 10 additions & 10 deletions examples/vanilla-ts/src/carousel.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as carousel from "@zag-js/carousel"
import { Component } from "./component"
import { normalizeProps, spreadProps, VanillaMachine } from "@zag-js/vanilla"
import { normalizeProps, VanillaMachine } from "@zag-js/vanilla"

export class Carousel extends Component<carousel.Props, carousel.Api> {
images: string[] = []
Expand Down Expand Up @@ -52,7 +52,7 @@ export class Carousel extends Component<carousel.Props, carousel.Api> {
}

// Update props
spreadProps(itemEl, this.api.getItemProps({ index }))
this.spreadProps(itemEl, this.api.getItemProps({ index }))

const img = itemEl.querySelector("img")
if (img) img.src = image
Expand Down Expand Up @@ -83,33 +83,33 @@ export class Carousel extends Component<carousel.Props, carousel.Api> {
}

// Update props
spreadProps(indicatorEl, this.api.getIndicatorProps({ index }))
this.spreadProps(indicatorEl, this.api.getIndicatorProps({ index }))
})
}

render() {
spreadProps(this.rootEl, this.api.getRootProps())
this.spreadProps(this.rootEl, this.api.getRootProps())

const control = this.rootEl.querySelector<HTMLElement>(".carousel-control")
if (control) spreadProps(control, this.api.getControlProps())
if (control) this.spreadProps(control, this.api.getControlProps())

const autoplayBtn = this.rootEl.querySelector<HTMLElement>(".carousel-autoplay")
if (autoplayBtn) {
spreadProps(autoplayBtn, this.api.getAutoplayTriggerProps())
this.spreadProps(autoplayBtn, this.api.getAutoplayTriggerProps())
autoplayBtn.textContent = this.api.isPlaying ? "Stop" : "Play"
}

const prevBtn = this.rootEl.querySelector<HTMLElement>(".carousel-prev")
if (prevBtn) spreadProps(prevBtn, this.api.getPrevTriggerProps())
if (prevBtn) this.spreadProps(prevBtn, this.api.getPrevTriggerProps())

const nextBtn = this.rootEl.querySelector<HTMLElement>(".carousel-next")
if (nextBtn) spreadProps(nextBtn, this.api.getNextTriggerProps())
if (nextBtn) this.spreadProps(nextBtn, this.api.getNextTriggerProps())

const itemGroup = this.rootEl.querySelector<HTMLElement>(".carousel-item-group")
if (itemGroup) spreadProps(itemGroup, this.api.getItemGroupProps())
if (itemGroup) this.spreadProps(itemGroup, this.api.getItemGroupProps())

const indicatorGroup = this.rootEl.querySelector<HTMLElement>(".carousel-indicator-group")
if (indicatorGroup) spreadProps(indicatorGroup, this.api.getIndicatorGroupProps())
if (indicatorGroup) this.spreadProps(indicatorGroup, this.api.getIndicatorGroupProps())

// Sync items and indicators
this.syncItems()
Expand Down
10 changes: 5 additions & 5 deletions examples/vanilla-ts/src/checkbox.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as checkbox from "@zag-js/checkbox"
import { normalizeProps, spreadProps, VanillaMachine } from "@zag-js/vanilla"
import { normalizeProps, VanillaMachine } from "@zag-js/vanilla"
import { Component } from "./component"

export class Checkbox extends Component<checkbox.Props, checkbox.Api> {
Expand All @@ -13,12 +13,12 @@ export class Checkbox extends Component<checkbox.Props, checkbox.Api> {

render = () => {
const rootEl = this.rootEl
spreadProps(this.rootEl, this.api.getRootProps())
this.spreadProps(this.rootEl, this.api.getRootProps())
const controlEl = rootEl.querySelector<HTMLElement>(".checkbox-control")
if (controlEl) spreadProps(controlEl, this.api.getControlProps())
if (controlEl) this.spreadProps(controlEl, this.api.getControlProps())
const labelEl = rootEl.querySelector<HTMLElement>(".checkbox-label")
if (labelEl) spreadProps(labelEl, this.api.getLabelProps())
if (labelEl) this.spreadProps(labelEl, this.api.getLabelProps())
const inputEl = rootEl.querySelector<HTMLInputElement>(".checkbox-input")
if (inputEl) spreadProps(inputEl, this.api.getHiddenInputProps())
if (inputEl) this.spreadProps(inputEl, this.api.getHiddenInputProps())
}
}
16 changes: 8 additions & 8 deletions examples/vanilla-ts/src/clipboard.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as clipboard from "@zag-js/clipboard"
import { Component } from "./component"
import { normalizeProps, spreadProps, VanillaMachine } from "@zag-js/vanilla"
import { normalizeProps, VanillaMachine } from "@zag-js/vanilla"

export class Clipboard extends Component<clipboard.Props, clipboard.Api> {
initMachine(props: clipboard.Props) {
Expand All @@ -14,34 +14,34 @@ export class Clipboard extends Component<clipboard.Props, clipboard.Api> {
}

render() {
spreadProps(this.rootEl, this.api.getRootProps())
this.spreadProps(this.rootEl, this.api.getRootProps())

const label = this.rootEl.querySelector<HTMLElement>(".clipboard-label")
if (label) spreadProps(label, this.api.getLabelProps())
if (label) this.spreadProps(label, this.api.getLabelProps())

const control = this.rootEl.querySelector<HTMLElement>(".clipboard-control")
if (control) spreadProps(control, this.api.getControlProps())
if (control) this.spreadProps(control, this.api.getControlProps())

const input = this.rootEl.querySelector<HTMLInputElement>(".clipboard-input")
if (input) {
spreadProps(input, this.api.getInputProps())
this.spreadProps(input, this.api.getInputProps())
}

const trigger = this.rootEl.querySelector<HTMLButtonElement>(".clipboard-trigger")
if (trigger) {
spreadProps(trigger, this.api.getTriggerProps())
this.spreadProps(trigger, this.api.getTriggerProps())
// Update button text based on copy state
trigger.textContent = this.api.copied ? "Copied!" : "Copy"
}

const copiedIndicator = this.rootEl.querySelector<HTMLElement>(".clipboard-copied-indicator")
if (copiedIndicator) {
spreadProps(copiedIndicator, this.api.getIndicatorProps({ copied: true }))
this.spreadProps(copiedIndicator, this.api.getIndicatorProps({ copied: true }))
}

const idleIndicator = this.rootEl.querySelector<HTMLElement>(".clipboard-idle-indicator")
if (idleIndicator) {
spreadProps(idleIndicator, this.api.getIndicatorProps({ copied: false }))
this.spreadProps(idleIndicator, this.api.getIndicatorProps({ copied: false }))
}
}
}
10 changes: 5 additions & 5 deletions examples/vanilla-ts/src/collapsible.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as collapsible from "@zag-js/collapsible"
import { Component } from "./component"
import { normalizeProps, spreadProps, VanillaMachine } from "@zag-js/vanilla"
import { normalizeProps, VanillaMachine } from "@zag-js/vanilla"

export class Collapsible extends Component<collapsible.Props, collapsible.Api> {
initMachine(props: collapsible.Props) {
Expand All @@ -14,16 +14,16 @@ export class Collapsible extends Component<collapsible.Props, collapsible.Api> {
}

render() {
spreadProps(this.rootEl, this.api.getRootProps())
this.spreadProps(this.rootEl, this.api.getRootProps())

const trigger = this.rootEl.querySelector<HTMLElement>(".collapsible-trigger")
if (trigger) spreadProps(trigger, this.api.getTriggerProps())
if (trigger) this.spreadProps(trigger, this.api.getTriggerProps())

const indicator = this.rootEl.querySelector<HTMLElement>(".collapsible-indicator")
if (indicator) spreadProps(indicator, this.api.getIndicatorProps())
if (indicator) this.spreadProps(indicator, this.api.getIndicatorProps())

const content = this.rootEl.querySelector<HTMLElement>(".collapsible-content")
if (content) spreadProps(content, this.api.getContentProps())
if (content) this.spreadProps(content, this.api.getContentProps())

// Control buttons (query from document since they're outside root)
const openBtn = this.doc.querySelector<HTMLElement>(".collapsible-open")
Expand Down
16 changes: 8 additions & 8 deletions examples/vanilla-ts/src/combobox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as combobox from "@zag-js/combobox"
import { comboboxData } from "@zag-js/shared"
import { matchSorter } from "match-sorter"
import { Component } from "./component"
import { normalizeProps, spreadProps, VanillaMachine } from "@zag-js/vanilla"
import { normalizeProps, VanillaMachine } from "@zag-js/vanilla"

interface Item {
code: string
Expand Down Expand Up @@ -65,27 +65,27 @@ export class Combobox extends Component<combobox.Props, combobox.Api> {
}

itemEl.innerText = item.label
spreadProps(itemEl, this.api.getItemProps({ item }))
this.spreadProps(itemEl, this.api.getItemProps({ item }))
})
}

render = () => {
spreadProps(this.rootEl, this.api.getRootProps())
this.spreadProps(this.rootEl, this.api.getRootProps())

const inputEl = this.rootEl?.querySelector<HTMLElement>(".combobox-input")
if (inputEl) spreadProps(inputEl, this.api.getInputProps())
if (inputEl) this.spreadProps(inputEl, this.api.getInputProps())

const triggerEl = this.rootEl?.querySelector<HTMLElement>(".combobox-trigger")
if (triggerEl) spreadProps(triggerEl, this.api.getTriggerProps())
if (triggerEl) this.spreadProps(triggerEl, this.api.getTriggerProps())

const clearTriggerEl = this.rootEl?.querySelector<HTMLElement>(".combobox-clear-trigger")
if (clearTriggerEl) spreadProps(clearTriggerEl, this.api.getClearTriggerProps())
if (clearTriggerEl) this.spreadProps(clearTriggerEl, this.api.getClearTriggerProps())

const controlEl = this.rootEl?.querySelector<HTMLElement>(".combobox-control")
if (controlEl) spreadProps(controlEl, this.api.getControlProps())
if (controlEl) this.spreadProps(controlEl, this.api.getControlProps())

const contentEl = this.getOrCreateContentEl()
spreadProps(contentEl, this.api.getContentProps())
this.spreadProps(contentEl, this.api.getContentProps())

this.renderItems()
}
Expand Down
11 changes: 10 additions & 1 deletion examples/vanilla-ts/src/component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { VanillaMachine } from "@zag-js/vanilla"
import { spreadProps, VanillaMachine } from "@zag-js/vanilla"
import type { Attrs } from "@zag-js/vanilla"

interface ComponentInterface<Api> {
rootEl: HTMLElement
Expand Down Expand Up @@ -42,5 +43,13 @@ export abstract class Component<Props, Api> implements ComponentInterface<Api> {
this.machine.stop()
}

spreadProps = (node: HTMLElement, attrs: Attrs) => {
spreadProps(node, attrs, this.machine.scope.id)
}

updateProps = (newProps: Partial<Props>) => {
this.machine.updateProps(newProps)
}

abstract render(): void
}
10 changes: 5 additions & 5 deletions examples/vanilla-ts/src/context-menu.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as menu from "@zag-js/menu"
import { Component } from "./component"
import { normalizeProps, spreadProps, VanillaMachine } from "@zag-js/vanilla"
import { normalizeProps, VanillaMachine } from "@zag-js/vanilla"

export class ContextMenu extends Component<menu.Props, menu.Api> {
initMachine(props: menu.Props) {
Expand All @@ -18,22 +18,22 @@ export class ContextMenu extends Component<menu.Props, menu.Api> {

render() {
const contextTrigger = this.rootEl.querySelector<HTMLElement>(".context-menu-trigger")
if (contextTrigger) spreadProps(contextTrigger, this.api.getContextTriggerProps())
if (contextTrigger) this.spreadProps(contextTrigger, this.api.getContextTriggerProps())

const positioner = this.rootEl.querySelector<HTMLElement>(".context-menu-positioner")
const content = this.rootEl.querySelector<HTMLElement>(".context-menu-content")

if (positioner && content) {
if (this.api.open) {
positioner.hidden = false
spreadProps(positioner, this.api.getPositionerProps())
spreadProps(content, this.api.getContentProps())
this.spreadProps(positioner, this.api.getPositionerProps())
this.spreadProps(content, this.api.getContentProps())

const items = content.querySelectorAll<HTMLElement>(".context-menu-item")
items.forEach((item) => {
const value = item.dataset.value
if (value) {
spreadProps(item, this.api.getItemProps({ value }))
this.spreadProps(item, this.api.getItemProps({ value }))
}
})
} else {
Expand Down
Loading
Loading