Packages
corex
0.1.1
0.1.2
0.1.1
0.1.0
0.1.0-rc.1
0.1.0-rc.0
0.1.0-beta.5
0.1.0-beta.4
0.1.0-beta.3
0.1.0-beta.2
0.1.0-beta.1
0.1.0-alpha.33
0.1.0-alpha.32
0.1.0-alpha.31
0.1.0-alpha.30
0.1.0-alpha.29
0.1.0-alpha.28
0.1.0-alpha.27
0.1.0-alpha.26
0.1.0-alpha.25
0.1.0-alpha.24
0.1.0-alpha.23
0.1.0-alpha.22
0.1.0-alpha.21
0.1.0-alpha.20
0.1.0-alpha.19
0.1.0-alpha.18
0.1.0-alpha.17
0.1.0-alpha.16
0.1.0-alpha.15
0.1.0-alpha.14
0.1.0-alpha.13
0.1.0-alpha.12
0.1.0-alpha.11
0.1.0-alpha.10
0.1.0-alpha.9
0.1.0-alpha.8
0.1.0-alpha.7
0.1.0-alpha.6
0.1.0-alpha.5
0.1.0-alpha.4
0.1.0-alpha.3
0.1.0-alpha.2
0.1.0-alpha.1
Accessible and unstyled UI components library written in Elixir and TypeScript that integrates Zag.js state machines into the Phoenix Framework.
Current section
Files
Jump to
Current section
Files
priv/static/avatar.mjs
import {
createDomEventRegistry,
createHookHandleEventRegistry
} from "./chunks/chunk-77HPO22C.mjs";
import {
emitResponse,
idMatches,
notifyChange,
parseRespondTo,
readPayloadId
} from "./chunks/chunk-2WCNJX5P.mjs";
import {
Component,
VanillaMachine,
canPushEvent,
createAnatomy,
createMachine,
getString,
observeAttributes,
observeChildren
} from "./chunks/chunk-2GQRP3FN.mjs";
// ../node_modules/.pnpm/@zag-js+avatar@1.40.0/node_modules/@zag-js/avatar/dist/avatar.anatomy.mjs
var anatomy = createAnatomy("avatar").parts("root", "image", "fallback");
var parts = anatomy.build();
// ../node_modules/.pnpm/@zag-js+avatar@1.40.0/node_modules/@zag-js/avatar/dist/avatar.dom.mjs
var getRootId = (ctx) => ctx.ids?.root ?? `avatar:${ctx.id}`;
var getImageId = (ctx) => ctx.ids?.image ?? `avatar:${ctx.id}:image`;
var getFallbackId = (ctx) => ctx.ids?.fallback ?? `avatar:${ctx.id}:fallback`;
var getRootEl = (ctx) => ctx.getById(getRootId(ctx));
var getImageEl = (ctx) => ctx.getById(getImageId(ctx));
// ../node_modules/.pnpm/@zag-js+avatar@1.40.0/node_modules/@zag-js/avatar/dist/avatar.connect.mjs
function connect(service, normalize) {
const { state, send, prop, scope } = service;
const loaded = state.matches("loaded");
return {
loaded,
setSrc(src) {
const img = getImageEl(scope);
img?.setAttribute("src", src);
},
setLoaded() {
send({ type: "img.loaded", src: "api" });
},
setError() {
send({ type: "img.error", src: "api" });
},
getRootProps() {
return normalize.element({
...parts.root.attrs,
dir: prop("dir"),
id: getRootId(scope)
});
},
getImageProps() {
return normalize.img({
...parts.image.attrs,
hidden: !loaded,
dir: prop("dir"),
id: getImageId(scope),
"data-state": loaded ? "visible" : "hidden",
onLoad() {
send({ type: "img.loaded", src: "element" });
},
onError() {
send({ type: "img.error", src: "element" });
}
});
},
getFallbackProps() {
return normalize.element({
...parts.fallback.attrs,
dir: prop("dir"),
id: getFallbackId(scope),
hidden: loaded,
"data-state": loaded ? "hidden" : "visible"
});
}
};
}
// ../node_modules/.pnpm/@zag-js+avatar@1.40.0/node_modules/@zag-js/avatar/dist/avatar.machine.mjs
var machine = createMachine({
initialState() {
return "loading";
},
effects: ["trackImageRemoval", "trackSrcChange"],
on: {
"src.change": {
target: "loading"
},
"img.unmount": {
target: "error"
}
},
states: {
loading: {
entry: ["checkImageStatus"],
on: {
"img.loaded": {
target: "loaded",
actions: ["invokeOnLoad"]
},
"img.error": {
target: "error",
actions: ["invokeOnError"]
}
}
},
error: {
on: {
"img.loaded": {
target: "loaded",
actions: ["invokeOnLoad"]
}
}
},
loaded: {
on: {
"img.error": {
target: "error",
actions: ["invokeOnError"]
}
}
}
},
implementations: {
actions: {
invokeOnLoad({ prop }) {
prop("onStatusChange")?.({ status: "loaded" });
},
invokeOnError({ prop }) {
prop("onStatusChange")?.({ status: "error" });
},
checkImageStatus({ send, scope }) {
const imageEl = getImageEl(scope);
if (!imageEl?.complete) return;
const type = hasLoaded(imageEl) ? "img.loaded" : "img.error";
send({ type, src: "ssr" });
}
},
effects: {
trackImageRemoval({ send, scope }) {
const rootEl = getRootEl(scope);
return observeChildren(rootEl, {
callback(records) {
const removedNodes = Array.from(records[0].removedNodes);
const removed = removedNodes.find(
(node) => node.nodeType === Node.ELEMENT_NODE && node.matches("[data-scope=avatar][data-part=image]")
);
if (removed) {
send({ type: "img.unmount" });
}
}
});
},
trackSrcChange({ send, scope }) {
const imageEl = getImageEl(scope);
return observeAttributes(imageEl, {
attributes: ["src", "srcset"],
callback() {
send({ type: "src.change" });
}
});
}
}
}
});
function hasLoaded(image) {
return image.complete && image.naturalWidth !== 0 && image.naturalHeight !== 0;
}
// components/avatar.ts
var Avatar = class extends Component {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
initMachine(props) {
return new VanillaMachine(machine, props);
}
initApi() {
return this.zagConnect(connect);
}
render() {
const rootEl = this.el.querySelector('[data-scope="avatar"][data-part="root"]') ?? this.el;
this.spreadProps(rootEl, this.api.getRootProps());
const imageEl = this.el.querySelector('[data-scope="avatar"][data-part="image"]');
if (imageEl) this.spreadProps(imageEl, this.api.getImageProps());
const fallbackEl = this.el.querySelector(
'[data-scope="avatar"][data-part="fallback"]'
);
if (fallbackEl) this.spreadProps(fallbackEl, this.api.getFallbackProps());
const skeletonEl = this.el.querySelector(
'[data-scope="avatar"][data-part="skeleton"]'
);
if (skeletonEl) {
const state = this.machine.service.state;
const loaded = state.matches("loaded");
const error = state.matches("error");
skeletonEl.hidden = loaded || error;
skeletonEl.setAttribute("data-state", loaded || error ? "hidden" : "visible");
}
}
};
// hooks/avatar.ts
function statusPayload(el, details) {
return { id: el.id, status: details.status };
}
var AvatarHook = {
mounted() {
const el = this.el;
const pushEvent = this.pushEvent.bind(this);
const canPush = () => canPushEvent(this.liveSocket);
const initialSrc = getString(el, "src");
const zag = new Avatar(el, {
id: el.id,
dir: getString(el, "dir"),
onStatusChange: (details) => {
const flat = statusPayload(el, details);
notifyChange({
el,
canPushServer: canPush(),
pushEvent,
payload: flat,
serverEventName: getString(el, "onStatusChange"),
clientEventName: getString(el, "onStatusChangeClient")
});
}
});
zag.init();
this.avatar = zag;
this.lastSrc = initialSrc;
const emitLoaded = (respondTo) => {
const loaded = zag.api.loaded;
emitResponse({
respondTo,
canPushServer: canPush(),
pushEvent,
serverEventName: "avatar_loaded_response",
serverPayload: { id: el.id, loaded },
el,
domEventName: "avatar-loaded",
domDetail: { id: el.id, loaded }
});
};
const domRegistry = createDomEventRegistry(el);
this.domRegistry = domRegistry;
domRegistry.add("corex:avatar:set-src", (event) => {
const next = event.detail?.src;
if (typeof next !== "string") return;
zag.api.setSrc(next);
this.lastSrc = next;
el.dataset.src = next;
});
domRegistry.add("corex:avatar:loaded", (event) => {
emitLoaded(parseRespondTo(event.detail));
});
const registry = createHookHandleEventRegistry(this);
this.handleRegistry = registry;
registry.add("avatar_set_src", (payload) => {
if (!idMatches(el.id, readPayloadId(payload))) return;
zag.api.setSrc(payload.src);
this.lastSrc = payload.src;
el.dataset.src = payload.src;
});
registry.add("avatar_loaded", (payload) => {
if (!idMatches(el.id, readPayloadId(payload))) return;
emitLoaded(parseRespondTo(payload));
});
},
updated() {
const src = getString(this.el, "src");
const dir = getString(this.el, "dir");
if (this.avatar) {
this.avatar.updateProps({
...dir !== void 0 ? { dir } : {}
});
}
if (this.avatar && src !== void 0 && src !== this.lastSrc) {
this.avatar.api.setSrc(src);
this.lastSrc = src;
}
if (this.avatar && src === void 0 && this.lastSrc !== void 0) {
this.avatar.api.setSrc("");
this.lastSrc = void 0;
}
},
destroyed() {
this.domRegistry?.teardown();
this.handleRegistry?.teardown();
this.avatar?.destroy();
}
};
export {
AvatarHook as Avatar,
statusPayload
};