@zag-js/avatar 0.0.0-dev-20230526205409 → 0.0.0-dev-20230526205955

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zag-js/avatar",
3
- "version": "0.0.0-dev-20230526205409",
3
+ "version": "0.0.0-dev-20230526205955",
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-20230526205409",
31
- "@zag-js/mutation-observer": "0.0.0-dev-20230526205409",
32
- "@zag-js/core": "0.0.0-dev-20230526205409",
33
- "@zag-js/dom-query": "0.0.0-dev-20230526205409",
34
- "@zag-js/utils": "0.0.0-dev-20230526205409",
35
- "@zag-js/types": "0.0.0-dev-20230526205409"
31
+ "@zag-js/anatomy": "0.0.0-dev-20230526205955",
32
+ "@zag-js/mutation-observer": "0.0.0-dev-20230526205955",
33
+ "@zag-js/core": "0.0.0-dev-20230526205955",
34
+ "@zag-js/dom-query": "0.0.0-dev-20230526205955",
35
+ "@zag-js/utils": "0.0.0-dev-20230526205955",
36
+ "@zag-js/types": "0.0.0-dev-20230526205955"
36
37
  },
37
38
  "devDependencies": {
38
39
  "clean-package": "2.2.0"
@@ -0,0 +1,5 @@
1
+ import { createAnatomy } from "@zag-js/anatomy"
2
+
3
+ export const anatomy = createAnatomy("avatar").parts("root", "image", "fallback")
4
+
5
+ export const parts = anatomy.build()
@@ -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
@@ -0,0 +1,3 @@
1
+ export { connect } from "./avatar.connect"
2
+ export { machine } from "./avatar.machine"
3
+ export type { UserDefinedContext as Context } from "./avatar.types"