@zag-js/avatar 0.0.0-dev-20230526205409 → 0.0.0-dev-20230526210710
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.
- package/package.json +9 -8
- package/src/avatar.anatomy.ts +5 -0
- package/src/avatar.connect.ts +74 -0
- package/src/avatar.dom.ts +11 -0
- package/src/avatar.machine.ts +90 -0
- package/src/avatar.types.ts +23 -0
- package/src/index.ts +3 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zag-js/avatar",
|
|
3
|
-
"version": "0.0.0-dev-
|
|
3
|
+
"version": "0.0.0-dev-20230526210710",
|
|
4
4
|
"description": "Core logic for the avatar widget implemented as a state machine",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"js",
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"repository": "https://github.com/chakra-ui/zag/tree/main/packages/avatar",
|
|
19
19
|
"sideEffects": false,
|
|
20
20
|
"files": [
|
|
21
|
-
"dist
|
|
21
|
+
"dist",
|
|
22
|
+
"src"
|
|
22
23
|
],
|
|
23
24
|
"publishConfig": {
|
|
24
25
|
"access": "public"
|
|
@@ -27,12 +28,12 @@
|
|
|
27
28
|
"url": "https://github.com/chakra-ui/zag/issues"
|
|
28
29
|
},
|
|
29
30
|
"dependencies": {
|
|
30
|
-
"@zag-js/anatomy": "0.0.0-dev-
|
|
31
|
-
"@zag-js/mutation-observer": "0.0.0-dev-
|
|
32
|
-
"@zag-js/core": "0.0.0-dev-
|
|
33
|
-
"@zag-js/dom-query": "0.0.0-dev-
|
|
34
|
-
"@zag-js/utils": "0.0.0-dev-
|
|
35
|
-
"@zag-js/types": "0.0.0-dev-
|
|
31
|
+
"@zag-js/anatomy": "0.0.0-dev-20230526210710",
|
|
32
|
+
"@zag-js/mutation-observer": "0.0.0-dev-20230526210710",
|
|
33
|
+
"@zag-js/core": "0.0.0-dev-20230526210710",
|
|
34
|
+
"@zag-js/dom-query": "0.0.0-dev-20230526210710",
|
|
35
|
+
"@zag-js/utils": "0.0.0-dev-20230526210710",
|
|
36
|
+
"@zag-js/types": "0.0.0-dev-20230526210710"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
38
39
|
"clean-package": "2.2.0"
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { dataAttr } from "@zag-js/dom-query"
|
|
2
|
+
import { NormalizeProps, type PropTypes } from "@zag-js/types"
|
|
3
|
+
import { parts } from "./avatar.anatomy"
|
|
4
|
+
import { dom } from "./avatar.dom"
|
|
5
|
+
import { Send, State } from "./avatar.types"
|
|
6
|
+
|
|
7
|
+
export function connect<T extends PropTypes>(state: State, send: Send, normalize: NormalizeProps<T>) {
|
|
8
|
+
const isLoaded = state.matches("loaded")
|
|
9
|
+
const showFallback = !isLoaded
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
/**
|
|
13
|
+
* Whether the image is loaded.
|
|
14
|
+
*/
|
|
15
|
+
isLoaded,
|
|
16
|
+
/**
|
|
17
|
+
* Whether the fallback is shown.
|
|
18
|
+
*/
|
|
19
|
+
showFallback,
|
|
20
|
+
/**
|
|
21
|
+
* Function to set new src.
|
|
22
|
+
*/
|
|
23
|
+
setSrc(src: string) {
|
|
24
|
+
send({ type: "SRC.SET", src })
|
|
25
|
+
},
|
|
26
|
+
/**
|
|
27
|
+
* Function to set loaded state.
|
|
28
|
+
*/
|
|
29
|
+
setLoaded() {
|
|
30
|
+
send({ type: "IMG.LOADED", src: "api" })
|
|
31
|
+
},
|
|
32
|
+
/**
|
|
33
|
+
* Function to set error state.
|
|
34
|
+
*/
|
|
35
|
+
setError() {
|
|
36
|
+
send({ type: "IMG.ERROR", src: "api" })
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
rootProps: normalize.element({
|
|
40
|
+
...parts.root.attrs,
|
|
41
|
+
id: dom.getRootId(state.context),
|
|
42
|
+
style: {
|
|
43
|
+
display: "grid",
|
|
44
|
+
gridTemplateRows: "1fr 1fr",
|
|
45
|
+
overflow: "hidden",
|
|
46
|
+
},
|
|
47
|
+
}),
|
|
48
|
+
|
|
49
|
+
imageProps: normalize.img({
|
|
50
|
+
...parts.image.attrs,
|
|
51
|
+
id: dom.getImageId(state.context),
|
|
52
|
+
"data-loaded": dataAttr(isLoaded),
|
|
53
|
+
onLoad() {
|
|
54
|
+
send({ type: "IMG.LOADED", src: "element" })
|
|
55
|
+
},
|
|
56
|
+
onError() {
|
|
57
|
+
send({ type: "IMG.ERROR", src: "element" })
|
|
58
|
+
},
|
|
59
|
+
style: {
|
|
60
|
+
gridArea: "1 / 1 / 2 / 2",
|
|
61
|
+
visibility: !isLoaded ? "hidden" : undefined,
|
|
62
|
+
},
|
|
63
|
+
}),
|
|
64
|
+
|
|
65
|
+
fallbackProps: normalize.element({
|
|
66
|
+
...parts.fallback.attrs,
|
|
67
|
+
id: dom.getFallbackId(state.context),
|
|
68
|
+
hidden: !showFallback,
|
|
69
|
+
style: {
|
|
70
|
+
gridArea: "1 / 1 / 2 / 2",
|
|
71
|
+
},
|
|
72
|
+
}),
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createScope } from "@zag-js/dom-query"
|
|
2
|
+
import type { MachineContext as Ctx } from "./avatar.types"
|
|
3
|
+
|
|
4
|
+
export const dom = createScope({
|
|
5
|
+
getRootId: (ctx: Ctx) => `avatar:${ctx.id}`,
|
|
6
|
+
getImageId: (ctx: Ctx) => `avatar:${ctx.id}:image`,
|
|
7
|
+
getFallbackId: (ctx: Ctx) => `avatar:${ctx.id}:fallback`,
|
|
8
|
+
|
|
9
|
+
getRootEl: (ctx: Ctx) => dom.getById(ctx, dom.getRootId(ctx)),
|
|
10
|
+
getImageEl: (ctx: Ctx) => dom.getById<HTMLImageElement>(ctx, dom.getImageId(ctx)),
|
|
11
|
+
})
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { createMachine } from "@zag-js/core"
|
|
2
|
+
import { compact } from "@zag-js/utils"
|
|
3
|
+
import { observeAttributes, observeChildren } from "@zag-js/mutation-observer"
|
|
4
|
+
import { MachineContext, MachineState, UserDefinedContext } from "./avatar.types"
|
|
5
|
+
import { dom } from "./avatar.dom"
|
|
6
|
+
|
|
7
|
+
export function machine(userContext: UserDefinedContext) {
|
|
8
|
+
const ctx = compact(userContext)
|
|
9
|
+
return createMachine<MachineContext, MachineState>(
|
|
10
|
+
{
|
|
11
|
+
id: "avatar",
|
|
12
|
+
initial: "loading",
|
|
13
|
+
activities: ["trackImageRemoval"],
|
|
14
|
+
|
|
15
|
+
context: ctx,
|
|
16
|
+
|
|
17
|
+
on: {
|
|
18
|
+
"SRC.CHANGE": {
|
|
19
|
+
target: "loading",
|
|
20
|
+
},
|
|
21
|
+
"IMG.UNMOUNT": {
|
|
22
|
+
target: "error",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
states: {
|
|
27
|
+
loading: {
|
|
28
|
+
activities: ["trackSrcChange"],
|
|
29
|
+
entry: ["checkImgStatus"],
|
|
30
|
+
on: {
|
|
31
|
+
"IMG.LOADED": {
|
|
32
|
+
target: "loaded",
|
|
33
|
+
actions: ["invokeOnLoad"],
|
|
34
|
+
},
|
|
35
|
+
"IMG.ERROR": {
|
|
36
|
+
target: "error",
|
|
37
|
+
actions: ["invokeOnError"],
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
error: {
|
|
42
|
+
activities: ["trackSrcChange"],
|
|
43
|
+
on: {
|
|
44
|
+
"IMG.LOADED": {
|
|
45
|
+
target: "loaded",
|
|
46
|
+
actions: ["invokeOnLoad"],
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
loaded: {
|
|
51
|
+
activities: ["trackSrcChange"],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
activities: {
|
|
57
|
+
trackSrcChange(ctx, _evt, { send }) {
|
|
58
|
+
const img = dom.getImageEl(ctx)
|
|
59
|
+
return observeAttributes(img, ["src", "srcset"], () => {
|
|
60
|
+
send({ type: "SRC.CHANGE" })
|
|
61
|
+
})
|
|
62
|
+
},
|
|
63
|
+
trackImageRemoval(ctx, _evt, { send }) {
|
|
64
|
+
const rootEl = dom.getRootEl(ctx)
|
|
65
|
+
return observeChildren(rootEl, (records) => {
|
|
66
|
+
const removedNodes = Array.from(records[0].removedNodes) as HTMLElement[]
|
|
67
|
+
const removed = removedNodes.find((node) => node.matches("[data-scope=avatar][data-part=image]"))
|
|
68
|
+
if (removed) {
|
|
69
|
+
send({ type: "IMG.UNMOUNT" })
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
actions: {
|
|
75
|
+
invokeOnLoad(ctx) {
|
|
76
|
+
ctx.onLoad?.()
|
|
77
|
+
},
|
|
78
|
+
invokeOnError(ctx) {
|
|
79
|
+
ctx.onError?.()
|
|
80
|
+
},
|
|
81
|
+
checkImgStatus(ctx, _evt, { send }) {
|
|
82
|
+
const img = dom.getImageEl(ctx)
|
|
83
|
+
if (img?.complete) {
|
|
84
|
+
send({ type: "IMG.LOADED", src: "ssr" })
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
)
|
|
90
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { StateMachine as S } from "@zag-js/core"
|
|
2
|
+
import type { CommonProperties, Context, RequiredBy } from "@zag-js/types"
|
|
3
|
+
|
|
4
|
+
type PublicContext = CommonProperties & {
|
|
5
|
+
onLoad?: () => void
|
|
6
|
+
onError?: () => void
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
type PrivateContext = Context<{}>
|
|
10
|
+
|
|
11
|
+
type ComputedContext = Readonly<{}>
|
|
12
|
+
|
|
13
|
+
export type UserDefinedContext = RequiredBy<PublicContext, "id">
|
|
14
|
+
|
|
15
|
+
export type MachineContext = PublicContext & PrivateContext & ComputedContext
|
|
16
|
+
|
|
17
|
+
export type MachineState = {
|
|
18
|
+
value: "loading" | "error" | "loaded"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type State = S.State<MachineContext, MachineState>
|
|
22
|
+
|
|
23
|
+
export type Send = S.Send<S.AnyEventObject>
|
package/src/index.ts
ADDED