@zag-js/toast 0.69.0 → 0.71.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.
@@ -1,130 +0,0 @@
1
- import { dataAttr } from "@zag-js/dom-query"
2
- import type { NormalizeProps, PropTypes } from "@zag-js/types"
3
- import { parts } from "./toast.anatomy"
4
- import { dom } from "./toast.dom"
5
- import type { MachineApi, Send, State } from "./toast.types"
6
- import { getGhostAfterStyle, getGhostBeforeStyle, getPlacementStyle } from "./toast.utils"
7
-
8
- export function connect<T extends PropTypes, O>(
9
- state: State<O>,
10
- send: Send,
11
- normalize: NormalizeProps<T>,
12
- ): MachineApi<T, O> {
13
- const visible = state.hasTag("visible")
14
- const paused = state.hasTag("paused")
15
-
16
- const placement = state.context.placement!
17
- const type = state.context.type!
18
-
19
- const [side, align = "center"] = placement.split("-")
20
-
21
- return {
22
- type: type,
23
- title: state.context.title,
24
- description: state.context.description,
25
- placement,
26
- visible: visible,
27
- paused: paused,
28
-
29
- pause() {
30
- send("PAUSE")
31
- },
32
-
33
- resume() {
34
- send("RESUME")
35
- },
36
-
37
- dismiss() {
38
- send("DISMISS")
39
- },
40
-
41
- getRootProps() {
42
- return normalize.element({
43
- ...parts.root.attrs,
44
- dir: state.context.dir,
45
- id: dom.getRootId(state.context),
46
- "data-state": visible ? "open" : "closed",
47
- "data-type": type,
48
- "data-placement": placement,
49
- "data-align": align,
50
- "data-side": side,
51
- "data-mounted": dataAttr(state.context.mounted),
52
- "data-paused": dataAttr(paused),
53
-
54
- "data-first": dataAttr(state.context.frontmost),
55
- "data-sibling": dataAttr(!state.context.frontmost),
56
- "data-stack": dataAttr(state.context.stacked),
57
- "data-overlap": dataAttr(!state.context.stacked),
58
-
59
- role: "status",
60
- "aria-atomic": "true",
61
- "aria-describedby": state.context.description ? dom.getDescriptionId(state.context) : undefined,
62
- "aria-labelledby": state.context.title ? dom.getTitleId(state.context) : undefined,
63
- tabIndex: 0,
64
- style: getPlacementStyle(state.context, visible),
65
- onKeyDown(event) {
66
- if (event.defaultPrevented) return
67
- if (event.key == "Escape") {
68
- send("DISMISS")
69
- event.preventDefault()
70
- }
71
- },
72
- })
73
- },
74
-
75
- /* Leave a ghost div to avoid setting hover to false when transitioning out */
76
- getGhostBeforeProps() {
77
- return normalize.element({
78
- "data-ghost": "before",
79
- style: getGhostBeforeStyle(state.context, visible),
80
- })
81
- },
82
-
83
- /* Needed to avoid setting hover to false when in between toasts */
84
- getGhostAfterProps() {
85
- return normalize.element({
86
- "data-ghost": "after",
87
- style: getGhostAfterStyle(state.context, visible),
88
- })
89
- },
90
-
91
- getTitleProps() {
92
- return normalize.element({
93
- ...parts.title.attrs,
94
- id: dom.getTitleId(state.context),
95
- })
96
- },
97
-
98
- getDescriptionProps() {
99
- return normalize.element({
100
- ...parts.description.attrs,
101
- id: dom.getDescriptionId(state.context),
102
- })
103
- },
104
-
105
- getActionTriggerProps() {
106
- return normalize.button({
107
- ...parts.actionTrigger.attrs,
108
- type: "button",
109
- onClick(event) {
110
- if (event.defaultPrevented) return
111
- state.context.action?.onClick?.()
112
- send("DISMISS")
113
- },
114
- })
115
- },
116
-
117
- getCloseTriggerProps() {
118
- return normalize.button({
119
- id: dom.getCloseTriggerId(state.context),
120
- ...parts.closeTrigger.attrs,
121
- type: "button",
122
- "aria-label": "Dismiss notification",
123
- onClick(event) {
124
- if (event.defaultPrevented) return
125
- send("DISMISS")
126
- },
127
- })
128
- },
129
- }
130
- }
package/src/toast.dom.ts DELETED
@@ -1,13 +0,0 @@
1
- import { createScope } from "@zag-js/dom-query"
2
- import type { MachineContext as Ctx, Placement, GroupMachineContext as GroupCtx } from "./toast.types"
3
-
4
- export const dom = createScope({
5
- getRegionId: (placement: Placement) => `toast-group:${placement}`,
6
- getRegionEl: (ctx: GroupCtx, placement: Placement) => dom.getById(ctx, `toast-group:${placement}`),
7
-
8
- getRootId: (ctx: Ctx) => `toast:${ctx.id}`,
9
- getRootEl: (ctx: Ctx) => dom.getById(ctx, dom.getRootId(ctx)),
10
- getTitleId: (ctx: Ctx) => `toast:${ctx.id}:title`,
11
- getDescriptionId: (ctx: Ctx) => `toast:${ctx.id}:description`,
12
- getCloseTriggerId: (ctx: Ctx) => `toast${ctx.id}:close`,
13
- })
@@ -1,216 +0,0 @@
1
- import { createMachine, guards } from "@zag-js/core"
2
- import { queryAll, raf } from "@zag-js/dom-query"
3
- import { compact, warn } from "@zag-js/utils"
4
- import { dom } from "./toast.dom"
5
- import type { MachineContext, MachineState, Options } from "./toast.types"
6
- import { getToastDuration } from "./toast.utils"
7
-
8
- const { not, and, or } = guards
9
-
10
- export function createToastMachine<T>(options: Options<T>) {
11
- const { type = "info", duration, id = "1", placement = "bottom", removeDelay = 200, ...restProps } = options
12
- const ctx = compact(restProps)
13
-
14
- const computedDuration = getToastDuration(duration, type)
15
-
16
- return createMachine<MachineContext<T>, MachineState>(
17
- {
18
- id,
19
- context: {
20
- id,
21
- type,
22
- remaining: computedDuration,
23
- duration: computedDuration,
24
- removeDelay,
25
- createdAt: Date.now(),
26
- placement,
27
- ...ctx,
28
- height: 0,
29
- offset: 0,
30
- frontmost: false,
31
- mounted: false,
32
- index: -1,
33
- zIndex: 0,
34
- },
35
-
36
- initial: type === "loading" ? "visible:persist" : "visible",
37
-
38
- on: {
39
- UPDATE: [
40
- {
41
- guard: and("hasTypeChanged", "isChangingToLoading"),
42
- target: "visible:persist",
43
- actions: ["setContext"],
44
- },
45
- {
46
- guard: or("hasDurationChanged", "hasTypeChanged"),
47
- target: "visible:updating",
48
- actions: ["setContext"],
49
- },
50
- {
51
- actions: ["setContext"],
52
- },
53
- ],
54
- MEASURE: {
55
- actions: ["measureHeight"],
56
- },
57
- },
58
-
59
- entry: ["invokeOnVisible"],
60
-
61
- activities: ["trackHeight"],
62
-
63
- states: {
64
- "visible:updating": {
65
- tags: ["visible", "updating"],
66
- after: {
67
- 0: "visible",
68
- },
69
- },
70
-
71
- "visible:persist": {
72
- tags: ["visible", "paused"],
73
- on: {
74
- RESUME: {
75
- guard: not("isLoadingType"),
76
- target: "visible",
77
- actions: ["setCreatedAt"],
78
- },
79
- DISMISS: "dismissing",
80
- },
81
- },
82
-
83
- visible: {
84
- tags: ["visible"],
85
- after: {
86
- VISIBLE_DURATION: "dismissing",
87
- },
88
- on: {
89
- DISMISS: "dismissing",
90
- PAUSE: {
91
- target: "visible:persist",
92
- actions: "setRemainingDuration",
93
- },
94
- },
95
- },
96
-
97
- dismissing: {
98
- entry: "invokeOnDismiss",
99
- after: {
100
- REMOVE_DELAY: {
101
- target: "unmounted",
102
- actions: "notifyParentToRemove",
103
- },
104
- },
105
- },
106
-
107
- unmounted: {
108
- entry: "invokeOnUnmount",
109
- type: "final",
110
- },
111
- },
112
- },
113
- {
114
- activities: {
115
- trackHeight(ctx, _evt, { self }) {
116
- let cleanup: VoidFunction
117
- raf(() => {
118
- const rootEl = dom.getRootEl(ctx)
119
- if (!rootEl) return
120
- ctx.mounted = true
121
-
122
- const ghosts = queryAll(rootEl, "[data-ghost]")
123
-
124
- warn(
125
- ghosts.length !== 2,
126
- "[toast] No ghost element found in toast. Render the `ghostBefore` and `ghostAfter` elements",
127
- )
128
-
129
- const syncHeight = () => {
130
- const originalHeight = rootEl.style.height
131
- rootEl.style.height = "auto"
132
- const newHeight = rootEl.getBoundingClientRect().height
133
- rootEl.style.height = originalHeight
134
-
135
- ctx.height = newHeight
136
- self.sendParent({ type: "UPDATE_HEIGHT", id: self.id, height: newHeight, placement: ctx.placement })
137
- }
138
-
139
- syncHeight()
140
-
141
- const win = dom.getWin(ctx)
142
-
143
- const observer = new win.MutationObserver(syncHeight)
144
- observer.observe(rootEl, { childList: true, subtree: true, characterData: true })
145
-
146
- cleanup = () => observer.disconnect()
147
- })
148
-
149
- return () => cleanup?.()
150
- },
151
- },
152
-
153
- guards: {
154
- isChangingToLoading: (_, evt) => evt.toast?.type === "loading",
155
- isLoadingType: (ctx) => ctx.type === "loading",
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
- },
159
-
160
- delays: {
161
- VISIBLE_DURATION: (ctx) => ctx.remaining,
162
- REMOVE_DELAY: (ctx) => ctx.removeDelay,
163
- },
164
-
165
- actions: {
166
- measureHeight(ctx, _evt, { self }) {
167
- raf(() => {
168
- const rootEl = dom.getRootEl(ctx)
169
- if (!rootEl) return
170
-
171
- ctx.mounted = true
172
-
173
- const originalHeight = rootEl.style.height
174
- rootEl.style.height = "auto"
175
-
176
- const newHeight = rootEl.getBoundingClientRect().height
177
- rootEl.style.height = originalHeight
178
- ctx.height = newHeight
179
-
180
- self.sendParent({ type: "UPDATE_HEIGHT", id: self.id, height: newHeight, placement: ctx.placement })
181
- })
182
- },
183
- setRemainingDuration(ctx) {
184
- ctx.remaining -= Date.now() - ctx.createdAt
185
- },
186
- setCreatedAt(ctx) {
187
- ctx.createdAt = Date.now()
188
- },
189
- notifyParentToRemove(_ctx, _evt, { self }) {
190
- self.sendParent({ type: "REMOVE_TOAST", id: self.id })
191
- },
192
- invokeOnDismiss(ctx) {
193
- ctx.onStatusChange?.({ status: "dismissing" })
194
- },
195
- invokeOnUnmount(ctx) {
196
- ctx.onStatusChange?.({ status: "unmounted" })
197
- },
198
- invokeOnVisible(ctx) {
199
- ctx.onStatusChange?.({ status: "visible" })
200
- },
201
- setContext(ctx, evt) {
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
- })
212
- },
213
- },
214
- },
215
- )
216
- }