@zag-js/toast 0.46.0 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,11 +10,11 @@ export function connect<T extends PropTypes, O>(
10
10
  send: Send,
11
11
  normalize: NormalizeProps<T>,
12
12
  ): MachineApi<T, O> {
13
- const isVisible = state.hasTag("visible")
14
- const isPaused = state.hasTag("paused")
13
+ const visible = state.hasTag("visible")
14
+ const paused = state.hasTag("paused")
15
15
 
16
16
  const placement = state.context.placement!
17
- const type = state.context.type
17
+ const type = state.context.type!
18
18
 
19
19
  const [side, align = "center"] = placement.split("-")
20
20
 
@@ -23,9 +23,8 @@ export function connect<T extends PropTypes, O>(
23
23
  title: state.context.title,
24
24
  description: state.context.description,
25
25
  placement,
26
- isVisible,
27
- isPaused,
28
- isRtl: state.context.dir === "rtl",
26
+ visible: visible,
27
+ paused: paused,
29
28
 
30
29
  pause() {
31
30
  send("PAUSE")
@@ -43,13 +42,13 @@ export function connect<T extends PropTypes, O>(
43
42
  ...parts.root.attrs,
44
43
  dir: state.context.dir,
45
44
  id: dom.getRootId(state.context),
46
- "data-state": isVisible ? "open" : "closed",
45
+ "data-state": visible ? "open" : "closed",
47
46
  "data-type": type,
48
47
  "data-placement": placement,
49
48
  "data-align": align,
50
49
  "data-side": side,
51
50
  "data-mounted": dataAttr(state.context.mounted),
52
- "data-paused": dataAttr(isPaused),
51
+ "data-paused": dataAttr(paused),
53
52
 
54
53
  "data-first": dataAttr(state.context.frontmost),
55
54
  "data-sibling": dataAttr(!state.context.frontmost),
@@ -59,8 +58,9 @@ export function connect<T extends PropTypes, O>(
59
58
  role: "status",
60
59
  "aria-atomic": "true",
61
60
  tabIndex: 0,
62
- style: getPlacementStyle(state.context, isVisible),
61
+ style: getPlacementStyle(state.context, visible),
63
62
  onKeyDown(event) {
63
+ if (event.defaultPrevented) return
64
64
  if (event.key == "Escape") {
65
65
  send("DISMISS")
66
66
  event.preventDefault()
@@ -70,16 +70,14 @@ export function connect<T extends PropTypes, O>(
70
70
 
71
71
  /* Leave a ghost div to avoid setting hover to false when transitioning out */
72
72
  ghostBeforeProps: normalize.element({
73
- ...parts.ghost.attrs,
74
- "data-type": "before",
75
- style: getGhostBeforeStyle(state.context, isVisible),
73
+ "data-ghost": "before",
74
+ style: getGhostBeforeStyle(state.context, visible),
76
75
  }),
77
76
 
78
77
  /* Needed to avoid setting hover to false when in between toasts */
79
78
  ghostAfterProps: normalize.element({
80
- ...parts.ghost.attrs,
81
- "data-type": "after",
82
- style: getGhostAfterStyle(state.context, isVisible),
79
+ "data-ghost": "after",
80
+ style: getGhostAfterStyle(state.context, visible),
83
81
  }),
84
82
 
85
83
  titleProps: normalize.element({
@@ -95,7 +93,8 @@ export function connect<T extends PropTypes, O>(
95
93
  actionTriggerProps: normalize.button({
96
94
  ...parts.actionTrigger.attrs,
97
95
  type: "button",
98
- onClick() {
96
+ onClick(event) {
97
+ if (event.defaultPrevented) return
99
98
  send("DISMISS")
100
99
  },
101
100
  }),
@@ -105,7 +104,8 @@ export function connect<T extends PropTypes, O>(
105
104
  ...parts.closeTrigger.attrs,
106
105
  type: "button",
107
106
  "aria-label": "Dismiss notification",
108
- onClick() {
107
+ onClick(event) {
108
+ if (event.defaultPrevented) return
109
109
  send("DISMISS")
110
110
  },
111
111
  }),
@@ -119,7 +119,7 @@ export function createToastMachine<T>(options: Options<T>) {
119
119
  if (!rootEl) return
120
120
  ctx.mounted = true
121
121
 
122
- const ghosts = queryAll(rootEl, "[data-part=ghost]")
122
+ const ghosts = queryAll(rootEl, "[data-ghost]")
123
123
 
124
124
  warn(
125
125
  ghosts.length !== 2,
@@ -129,7 +129,7 @@ export function createToastMachine<T>(options: Options<T>) {
129
129
  const syncHeight = () => {
130
130
  const originalHeight = rootEl.style.height
131
131
  rootEl.style.height = "auto"
132
- const newHeight = rootEl.offsetHeight
132
+ const newHeight = rootEl.getBoundingClientRect().height
133
133
  rootEl.style.height = originalHeight
134
134
 
135
135
  ctx.height = newHeight
@@ -153,8 +153,8 @@ export function createToastMachine<T>(options: Options<T>) {
153
153
  guards: {
154
154
  isChangingToLoading: (_, evt) => evt.toast?.type === "loading",
155
155
  isLoadingType: (ctx) => ctx.type === "loading",
156
- hasTypeChanged: (ctx, evt) => evt.toast?.type !== ctx.type,
157
- hasDurationChanged: (ctx, evt) => evt.toast?.duration !== ctx.duration,
156
+ hasTypeChanged: (ctx, evt) => evt.toast?.type != null && evt.toast.type !== ctx.type,
157
+ hasDurationChanged: (ctx, evt) => evt.toast?.duration != null && evt.toast.duration !== ctx.duration,
158
158
  },
159
159
 
160
160
  delays: {
@@ -173,7 +173,7 @@ export function createToastMachine<T>(options: Options<T>) {
173
173
  const originalHeight = rootEl.style.height
174
174
  rootEl.style.height = "auto"
175
175
 
176
- const newHeight = rootEl.offsetHeight
176
+ const newHeight = rootEl.getBoundingClientRect().height
177
177
  rootEl.style.height = originalHeight
178
178
  ctx.height = newHeight
179
179
 
@@ -199,13 +199,16 @@ export function createToastMachine<T>(options: Options<T>) {
199
199
  ctx.onStatusChange?.({ status: "visible" })
200
200
  },
201
201
  setContext(ctx, evt) {
202
- const { duration, type } = evt.toast
203
- if (duration == null && type == null) {
204
- Object.assign(ctx, evt.toast)
205
- } else {
206
- const time = getToastDuration(duration, type)
207
- Object.assign(ctx, { ...evt.toast, duration: time, remaining: time })
208
- }
202
+ const duration = evt.toast?.duration
203
+ const type = evt.toast?.type ?? ctx.type
204
+
205
+ const computedDuration = getToastDuration(duration, type)
206
+
207
+ Object.assign(ctx, {
208
+ ...evt.toast,
209
+ duration: computedDuration,
210
+ remaining: computedDuration,
211
+ })
209
212
  },
210
213
  },
211
214
  },
@@ -56,7 +56,7 @@ export interface Options<T> extends GenericOptions<T> {
56
56
  /**
57
57
  * The type of the toast
58
58
  */
59
- type: Type
59
+ type?: Type
60
60
  /**
61
61
  * Function called when the toast is visible
62
62
  */
@@ -267,13 +267,13 @@ export interface GroupMachineApi<T extends PropTypes = PropTypes, O = any> {
267
267
  */
268
268
  getCount(): number
269
269
  /**
270
- * The active toasts
270
+ * The placements of the active toasts
271
271
  */
272
- getToasts(): Service<O>[]
272
+ getPlacements(): Placement[]
273
273
  /**
274
274
  * The active toasts by placement
275
275
  */
276
- getToastsByPlacement(): Partial<Record<Placement, Service<O>[]>>
276
+ getToastsByPlacement(placement: Placement): Service<O>[]
277
277
  /**
278
278
  * Returns whether the toast id is visible
279
279
  */
@@ -353,15 +353,11 @@ export interface MachineApi<T extends PropTypes = PropTypes, O = any> extends Ge
353
353
  /**
354
354
  * Whether the toast is visible.
355
355
  */
356
- isVisible: boolean
356
+ visible: boolean
357
357
  /**
358
358
  * Whether the toast is paused.
359
359
  */
360
- isPaused: boolean
361
- /**
362
- * Whether the toast is in RTL mode.
363
- */
364
- isRtl: boolean
360
+ paused: boolean
365
361
  /**
366
362
  * Function to pause the toast (keeping it visible).
367
363
  */
@@ -2,16 +2,8 @@ import { MAX_Z_INDEX } from "@zag-js/dom-query"
2
2
  import type { Style } from "@zag-js/types"
3
3
  import type { GroupMachineContext, MachineContext, Placement, Service, Type } from "./toast.types"
4
4
 
5
- export function getToastsByPlacement<T>(toasts: Service<T>[]) {
6
- const result: Partial<Record<Placement, Service<T>[]>> = {}
7
-
8
- for (const toast of toasts) {
9
- const placement = toast.state.context.placement!
10
- result[placement] ||= []
11
- result[placement]!.push(toast)
12
- }
13
-
14
- return result
5
+ export function getToastsByPlacement<T>(toasts: Service<T>[], placement: Placement) {
6
+ return toasts.filter((toast) => toast.state.context.placement === placement)
15
7
  }
16
8
 
17
9
  export const defaultTimeouts: Record<Type, number> = {
@@ -22,7 +14,7 @@ export const defaultTimeouts: Record<Type, number> = {
22
14
  DEFAULT: 5000,
23
15
  }
24
16
 
25
- export function getToastDuration(duration: number | undefined, type: MachineContext["type"]) {
17
+ export function getToastDuration(duration: number | undefined, type: NonNullable<MachineContext["type"]>) {
26
18
  return duration ?? defaultTimeouts[type] ?? defaultTimeouts.DEFAULT
27
19
  }
28
20