@zag-js/collapsible
Advanced tools
Comparing version 0.0.0-dev-20240220140757 to 0.0.0-dev-20240222152205
@@ -55,2 +55,6 @@ import * as _zag_js_anatomy from '@zag-js/anatomy'; | ||
/** | ||
* Whether the collapsible is visible (open or closing) | ||
*/ | ||
isVisible: boolean; | ||
/** | ||
* Whether the collapsible is disabled | ||
@@ -76,2 +80,5 @@ */ | ||
export { type MachineApi as Api, type UserDefinedContext as Context, type ElementIds, type OpenChangeDetails, anatomy, connect, machine }; | ||
declare const props: ("dir" | "open" | "disabled" | "id" | "ids" | "onOpenChange" | "open.controlled" | "getRootNode")[]; | ||
declare const splitProps: <Props extends Partial<UserDefinedContext>>(props: Props) => [Partial<UserDefinedContext>, Omit<Props, "dir" | "open" | "disabled" | "id" | "ids" | "onOpenChange" | "open.controlled" | "getRootNode">]; | ||
export { type MachineApi as Api, type UserDefinedContext as Context, type ElementIds, type OpenChangeDetails, anatomy, connect, machine, props, splitProps }; |
@@ -25,3 +25,5 @@ "use strict"; | ||
connect: () => connect, | ||
machine: () => machine | ||
machine: () => machine, | ||
props: () => props, | ||
splitProps: () => splitProps | ||
}); | ||
@@ -55,6 +57,7 @@ module.exports = __toCommonJS(src_exports); | ||
const width = state.context.width; | ||
const disabled = state.context.disabled; | ||
const skipDataAttr = state.context.isMountAnimationPrevented && isOpen; | ||
const isDisabled = !!state.context.disabled; | ||
const skipMountAnimation = state.context.isMountAnimationPrevented && isOpen; | ||
return { | ||
isDisabled: !!disabled, | ||
isDisabled, | ||
isVisible, | ||
isOpen, | ||
@@ -69,3 +72,3 @@ open() { | ||
...parts.root.attrs, | ||
"data-state": isVisible ? "open" : "closed", | ||
"data-state": isOpen ? "open" : "closed", | ||
dir: state.context.dir, | ||
@@ -76,5 +79,5 @@ id: dom.getRootId(state.context) | ||
...parts.content.attrs, | ||
"data-state": skipDataAttr ? void 0 : isOpen ? "open" : "closed", | ||
"data-state": skipMountAnimation ? void 0 : isOpen ? "open" : "closed", | ||
id: dom.getContentId(state.context), | ||
"data-disabled": (0, import_dom_query2.dataAttr)(disabled), | ||
"data-disabled": (0, import_dom_query2.dataAttr)(isDisabled), | ||
hidden: !isVisible, | ||
@@ -91,7 +94,8 @@ style: { | ||
type: "button", | ||
"data-disabled": (0, import_dom_query2.dataAttr)(disabled), | ||
"data-state": isOpen ? "open" : "closed", | ||
"data-disabled": (0, import_dom_query2.dataAttr)(isDisabled), | ||
"aria-controls": dom.getContentId(state.context), | ||
"aria-expanded": isVisible || false, | ||
onClick() { | ||
if (disabled) | ||
if (isDisabled) | ||
return; | ||
@@ -122,7 +126,5 @@ send({ type: isOpen ? "CLOSE" : "OPEN", src: "trigger.click" }); | ||
watch: { | ||
open: ["toggleVisibility"] | ||
open: ["allowAnimation", "toggleVisibility"] | ||
}, | ||
entry: ["computeSize"], | ||
exit: ["clearAnimationStyles"], | ||
activities: ["trackMountAnimation"], | ||
states: { | ||
@@ -133,6 +135,15 @@ closed: { | ||
on: { | ||
"CONTROLLED.OPEN": "open", | ||
"CONTROLLED.OPEN": { | ||
target: "open", | ||
actions: ["computeSize"] | ||
}, | ||
OPEN: [ | ||
{ guard: "isOpenControlled", actions: ["invokeOnOpen"] }, | ||
{ target: "open", actions: ["invokeOnOpen"] } | ||
{ | ||
guard: "isOpenControlled", | ||
actions: ["invokeOnOpen"] | ||
}, | ||
{ | ||
target: "open", | ||
actions: ["allowAnimation", "invokeOnOpen"] | ||
} | ||
] | ||
@@ -148,8 +159,20 @@ } | ||
OPEN: [ | ||
{ guard: "isOpenControlled", actions: ["invokeOnOpen"] }, | ||
{ target: "open", actions: ["invokeOnOpen"] } | ||
{ | ||
guard: "isOpenControlled", | ||
actions: ["invokeOnOpen"] | ||
}, | ||
{ | ||
target: "open", | ||
actions: ["allowAnimation", "invokeOnOpen"] | ||
} | ||
], | ||
CLOSE: [ | ||
{ guard: "isOpenControlled", actions: ["invokeOnClose"] }, | ||
{ target: "closed", actions: ["computeSize"] } | ||
{ | ||
guard: "isOpenControlled", | ||
actions: ["invokeOnClose"] | ||
}, | ||
{ | ||
target: "closed", | ||
actions: ["allowAnimation", "computeSize"] | ||
} | ||
], | ||
@@ -162,6 +185,15 @@ "ANIMATION.END": "closed" | ||
on: { | ||
"CONTROLLED.CLOSE": { target: "closing", actions: ["computeSize"] }, | ||
"CONTROLLED.CLOSE": { | ||
target: "closing", | ||
actions: ["computeSize"] | ||
}, | ||
CLOSE: [ | ||
{ guard: "isOpenControlled", actions: ["invokeOnClose"] }, | ||
{ target: "closing", actions: ["computeSize"] } | ||
{ | ||
guard: "isOpenControlled", | ||
actions: ["invokeOnClose"] | ||
}, | ||
{ | ||
target: "closing", | ||
actions: ["allowAnimation", "computeSize"] | ||
} | ||
] | ||
@@ -177,25 +209,28 @@ } | ||
activities: { | ||
trackMountAnimation(ctx2) { | ||
const cleanup = (0, import_dom_query3.raf)(() => { | ||
ctx2.isMountAnimationPrevented = false; | ||
}); | ||
return () => { | ||
ctx2.isMountAnimationPrevented = true; | ||
cleanup(); | ||
}; | ||
}, | ||
trackAnimationEvents(ctx2, _evt, { send }) { | ||
const contentEl = dom.getContentEl(ctx2); | ||
if (!contentEl) | ||
return; | ||
const onEnd = (event) => { | ||
if (event.target !== contentEl) | ||
let cleanup; | ||
const rafCleanup = (0, import_dom_query3.raf)(() => { | ||
const contentEl = dom.getContentEl(ctx2); | ||
if (!contentEl) | ||
return; | ||
send({ type: "ANIMATION.END" }); | ||
}; | ||
contentEl.addEventListener("animationend", onEnd); | ||
contentEl.addEventListener("animationcancel", onEnd); | ||
const isAnimationNone = (0, import_dom_query3.getComputedStyle)(contentEl).animationName === "none"; | ||
if (isAnimationNone) { | ||
send({ type: "ANIMATION.END" }); | ||
return; | ||
} | ||
const onEnd = (event) => { | ||
if (event.target !== contentEl) | ||
return; | ||
send({ type: "ANIMATION.END" }); | ||
}; | ||
contentEl.addEventListener("animationend", onEnd); | ||
contentEl.addEventListener("animationcancel", onEnd); | ||
cleanup = () => { | ||
contentEl.removeEventListener("animationend", onEnd); | ||
contentEl.removeEventListener("animationcancel", onEnd); | ||
}; | ||
}); | ||
return () => { | ||
contentEl.removeEventListener("animationend", onEnd); | ||
contentEl.removeEventListener("animationcancel", onEnd); | ||
rafCleanup(); | ||
cleanup?.(); | ||
}; | ||
@@ -205,22 +240,27 @@ } | ||
actions: { | ||
allowAnimation(ctx2) { | ||
ctx2.isMountAnimationPrevented = false; | ||
}, | ||
computeSize: (ctx2) => { | ||
const contentEl = dom.getContentEl(ctx2); | ||
if (!contentEl) | ||
return; | ||
ctx2.stylesRef || (ctx2.stylesRef = (0, import_core.ref)({ | ||
animationName: contentEl.style.animationName, | ||
animationDuration: contentEl.style.animationDuration | ||
})); | ||
const hidden = contentEl.hidden; | ||
contentEl.style.animationName = "none"; | ||
contentEl.style.animationDuration = "0s"; | ||
contentEl.hidden = false; | ||
const rect = contentEl.getBoundingClientRect(); | ||
ctx2.height = rect.height; | ||
ctx2.width = rect.width; | ||
if (!ctx2.isMountAnimationPrevented) { | ||
contentEl.style.animationName = ctx2.stylesRef.animationName; | ||
contentEl.style.animationDuration = ctx2.stylesRef.animationDuration; | ||
} | ||
contentEl.hidden = hidden; | ||
(0, import_dom_query3.raf)(() => { | ||
const contentEl = dom.getContentEl(ctx2); | ||
if (!contentEl) | ||
return; | ||
ctx2.stylesRef || (ctx2.stylesRef = (0, import_core.ref)({ | ||
animationName: contentEl.style.animationName, | ||
animationDuration: contentEl.style.animationDuration | ||
})); | ||
const hidden = contentEl.hidden; | ||
contentEl.style.animationName = "none"; | ||
contentEl.style.animationDuration = "0s"; | ||
contentEl.hidden = false; | ||
const rect = contentEl.getBoundingClientRect(); | ||
ctx2.height = rect.height; | ||
ctx2.width = rect.width; | ||
if (!ctx2.isMountAnimationPrevented) { | ||
contentEl.style.animationName = ctx2.stylesRef.animationName; | ||
contentEl.style.animationDuration = ctx2.stylesRef.animationDuration; | ||
} | ||
contentEl.hidden = hidden; | ||
}); | ||
}, | ||
@@ -235,11 +275,2 @@ invokeOnOpen: (ctx2) => { | ||
send({ type: ctx2.open ? "CONTROLLED.OPEN" : "CONTROLLED.CLOSE" }); | ||
}, | ||
clearAnimationStyles: (ctx2) => { | ||
const contentEl = dom.getContentEl(ctx2); | ||
if (!contentEl) | ||
return; | ||
(0, import_dom_query3.raf)(() => { | ||
contentEl.style.animationName = ""; | ||
contentEl.style.animationDuration = ""; | ||
}); | ||
} | ||
@@ -250,2 +281,17 @@ } | ||
} | ||
// src/collapsible.props.ts | ||
var import_types = require("@zag-js/types"); | ||
var import_utils2 = require("@zag-js/utils"); | ||
var props = (0, import_types.createProps)()([ | ||
"dir", | ||
"disabled", | ||
"getRootNode", | ||
"id", | ||
"ids", | ||
"onOpenChange", | ||
"open.controlled", | ||
"open" | ||
]); | ||
var splitProps = (0, import_utils2.createSplitProps)(props); | ||
// Annotate the CommonJS export names for ESM import in node: | ||
@@ -255,4 +301,6 @@ 0 && (module.exports = { | ||
connect, | ||
machine | ||
machine, | ||
props, | ||
splitProps | ||
}); | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@zag-js/collapsible", | ||
"version": "0.0.0-dev-20240220140757", | ||
"version": "0.0.0-dev-20240222152205", | ||
"description": "Core logic for the collapsible widget implemented as a state machine", | ||
@@ -31,7 +31,7 @@ "keywords": [ | ||
"dependencies": { | ||
"@zag-js/anatomy": "0.0.0-dev-20240220140757", | ||
"@zag-js/core": "0.0.0-dev-20240220140757", | ||
"@zag-js/dom-query": "0.0.0-dev-20240220140757", | ||
"@zag-js/utils": "0.0.0-dev-20240220140757", | ||
"@zag-js/types": "0.0.0-dev-20240220140757" | ||
"@zag-js/anatomy": "0.0.0-dev-20240222152205", | ||
"@zag-js/core": "0.0.0-dev-20240222152205", | ||
"@zag-js/dom-query": "0.0.0-dev-20240222152205", | ||
"@zag-js/utils": "0.0.0-dev-20240222152205", | ||
"@zag-js/types": "0.0.0-dev-20240222152205" | ||
}, | ||
@@ -38,0 +38,0 @@ "devDependencies": { |
@@ -13,8 +13,9 @@ import { dataAttr } from "@zag-js/dom-query" | ||
const width = state.context.width | ||
const disabled = state.context.disabled | ||
const isDisabled = !!state.context.disabled | ||
const skipDataAttr = state.context.isMountAnimationPrevented && isOpen | ||
const skipMountAnimation = state.context.isMountAnimationPrevented && isOpen | ||
return { | ||
isDisabled: !!disabled, | ||
isDisabled, | ||
isVisible, | ||
isOpen, | ||
@@ -30,3 +31,3 @@ open() { | ||
...parts.root.attrs, | ||
"data-state": isVisible ? "open" : "closed", | ||
"data-state": isOpen ? "open" : "closed", | ||
dir: state.context.dir, | ||
@@ -38,5 +39,5 @@ id: dom.getRootId(state.context), | ||
...parts.content.attrs, | ||
"data-state": skipDataAttr ? undefined : isOpen ? "open" : "closed", | ||
"data-state": skipMountAnimation ? undefined : isOpen ? "open" : "closed", | ||
id: dom.getContentId(state.context), | ||
"data-disabled": dataAttr(disabled), | ||
"data-disabled": dataAttr(isDisabled), | ||
hidden: !isVisible, | ||
@@ -54,7 +55,8 @@ style: { | ||
type: "button", | ||
"data-disabled": dataAttr(disabled), | ||
"data-state": isOpen ? "open" : "closed", | ||
"data-disabled": dataAttr(isDisabled), | ||
"aria-controls": dom.getContentId(state.context), | ||
"aria-expanded": isVisible || false, | ||
onClick() { | ||
if (disabled) return | ||
if (isDisabled) return | ||
send({ type: isOpen ? "CLOSE" : "OPEN", src: "trigger.click" }) | ||
@@ -61,0 +63,0 @@ }, |
import { createMachine, ref } from "@zag-js/core" | ||
import { raf } from "@zag-js/dom-query" | ||
import { getComputedStyle, raf } from "@zag-js/dom-query" | ||
import { compact } from "@zag-js/utils" | ||
@@ -23,10 +23,7 @@ import { dom } from "./collapsible.dom" | ||
watch: { | ||
open: ["toggleVisibility"], | ||
open: ["allowAnimation", "toggleVisibility"], | ||
}, | ||
entry: ["computeSize"], | ||
exit: ["clearAnimationStyles"], | ||
activities: ["trackMountAnimation"], | ||
states: { | ||
@@ -37,6 +34,15 @@ closed: { | ||
on: { | ||
"CONTROLLED.OPEN": "open", | ||
"CONTROLLED.OPEN": { | ||
target: "open", | ||
actions: ["computeSize"], | ||
}, | ||
OPEN: [ | ||
{ guard: "isOpenControlled", actions: ["invokeOnOpen"] }, | ||
{ target: "open", actions: ["invokeOnOpen"] }, | ||
{ | ||
guard: "isOpenControlled", | ||
actions: ["invokeOnOpen"], | ||
}, | ||
{ | ||
target: "open", | ||
actions: ["allowAnimation", "invokeOnOpen"], | ||
}, | ||
], | ||
@@ -53,8 +59,20 @@ }, | ||
OPEN: [ | ||
{ guard: "isOpenControlled", actions: ["invokeOnOpen"] }, | ||
{ target: "open", actions: ["invokeOnOpen"] }, | ||
{ | ||
guard: "isOpenControlled", | ||
actions: ["invokeOnOpen"], | ||
}, | ||
{ | ||
target: "open", | ||
actions: ["allowAnimation", "invokeOnOpen"], | ||
}, | ||
], | ||
CLOSE: [ | ||
{ guard: "isOpenControlled", actions: ["invokeOnClose"] }, | ||
{ target: "closed", actions: ["computeSize"] }, | ||
{ | ||
guard: "isOpenControlled", | ||
actions: ["invokeOnClose"], | ||
}, | ||
{ | ||
target: "closed", | ||
actions: ["allowAnimation", "computeSize"], | ||
}, | ||
], | ||
@@ -68,6 +86,15 @@ "ANIMATION.END": "closed", | ||
on: { | ||
"CONTROLLED.CLOSE": { target: "closing", actions: ["computeSize"] }, | ||
"CONTROLLED.CLOSE": { | ||
target: "closing", | ||
actions: ["computeSize"], | ||
}, | ||
CLOSE: [ | ||
{ guard: "isOpenControlled", actions: ["invokeOnClose"] }, | ||
{ target: "closing", actions: ["computeSize"] }, | ||
{ | ||
guard: "isOpenControlled", | ||
actions: ["invokeOnClose"], | ||
}, | ||
{ | ||
target: "closing", | ||
actions: ["allowAnimation", "computeSize"], | ||
}, | ||
], | ||
@@ -83,25 +110,34 @@ }, | ||
activities: { | ||
trackMountAnimation(ctx) { | ||
const cleanup = raf(() => { | ||
ctx.isMountAnimationPrevented = false | ||
}) | ||
return () => { | ||
ctx.isMountAnimationPrevented = true | ||
cleanup() | ||
} | ||
}, | ||
trackAnimationEvents(ctx, _evt, { send }) { | ||
const contentEl = dom.getContentEl(ctx) | ||
if (!contentEl) return | ||
let cleanup: VoidFunction | undefined | ||
const onEnd = (event: AnimationEvent) => { | ||
if (event.target !== contentEl) return | ||
send({ type: "ANIMATION.END" }) | ||
} | ||
const rafCleanup = raf(() => { | ||
const contentEl = dom.getContentEl(ctx) | ||
if (!contentEl) return | ||
contentEl.addEventListener("animationend", onEnd) | ||
contentEl.addEventListener("animationcancel", onEnd) | ||
// if there's no animation, send ANIMATION.END immediately | ||
const isAnimationNone = getComputedStyle(contentEl).animationName === "none" | ||
if (isAnimationNone) { | ||
send({ type: "ANIMATION.END" }) | ||
return | ||
} | ||
const onEnd = (event: AnimationEvent) => { | ||
if (event.target !== contentEl) return | ||
send({ type: "ANIMATION.END" }) | ||
} | ||
contentEl.addEventListener("animationend", onEnd) | ||
contentEl.addEventListener("animationcancel", onEnd) | ||
cleanup = () => { | ||
contentEl.removeEventListener("animationend", onEnd) | ||
contentEl.removeEventListener("animationcancel", onEnd) | ||
} | ||
}) | ||
return () => { | ||
contentEl.removeEventListener("animationend", onEnd) | ||
contentEl.removeEventListener("animationcancel", onEnd) | ||
rafCleanup() | ||
cleanup?.() | ||
} | ||
@@ -111,29 +147,34 @@ }, | ||
actions: { | ||
allowAnimation(ctx) { | ||
ctx.isMountAnimationPrevented = false | ||
}, | ||
computeSize: (ctx) => { | ||
const contentEl = dom.getContentEl(ctx) | ||
if (!contentEl) return | ||
raf(() => { | ||
const contentEl = dom.getContentEl(ctx) | ||
if (!contentEl) return | ||
ctx.stylesRef ||= ref({ | ||
animationName: contentEl.style.animationName, | ||
animationDuration: contentEl.style.animationDuration, | ||
}) | ||
ctx.stylesRef ||= ref({ | ||
animationName: contentEl.style.animationName, | ||
animationDuration: contentEl.style.animationDuration, | ||
}) | ||
const hidden = contentEl.hidden | ||
const hidden = contentEl.hidden | ||
// block any animations/transitions so the element renders at its full dimensions | ||
contentEl.style.animationName = "none" | ||
contentEl.style.animationDuration = "0s" | ||
contentEl.hidden = false | ||
// block any animations/transitions so the element renders at its full dimensions | ||
contentEl.style.animationName = "none" | ||
contentEl.style.animationDuration = "0s" | ||
contentEl.hidden = false | ||
const rect = contentEl.getBoundingClientRect() | ||
ctx.height = rect.height | ||
ctx.width = rect.width | ||
const rect = contentEl.getBoundingClientRect() | ||
ctx.height = rect.height | ||
ctx.width = rect.width | ||
// kick off any animations/transitions that were originally set up if it isn't the initial mount | ||
if (!ctx.isMountAnimationPrevented) { | ||
contentEl.style.animationName = ctx.stylesRef.animationName | ||
contentEl.style.animationDuration = ctx.stylesRef.animationDuration | ||
} | ||
// kick off any animations/transitions that were originally set up if it isn't the initial mount | ||
if (!ctx.isMountAnimationPrevented) { | ||
contentEl.style.animationName = ctx.stylesRef.animationName | ||
contentEl.style.animationDuration = ctx.stylesRef.animationDuration | ||
} | ||
contentEl.hidden = hidden | ||
contentEl.hidden = hidden | ||
}) | ||
}, | ||
@@ -149,11 +190,2 @@ invokeOnOpen: (ctx) => { | ||
}, | ||
clearAnimationStyles: (ctx) => { | ||
// cleanup any animation properties that were set (esp for React.StrictMode) | ||
const contentEl = dom.getContentEl(ctx) | ||
if (!contentEl) return | ||
raf(() => { | ||
contentEl.style.animationName = "" | ||
contentEl.style.animationDuration = "" | ||
}) | ||
}, | ||
}, | ||
@@ -160,0 +192,0 @@ }, |
import { createProps } from "@zag-js/types" | ||
import { createSplitProps } from "@zag-js/utils" | ||
import type { UserDefinedContext } from "./collapsible.types" | ||
@@ -14,1 +15,3 @@ | ||
]) | ||
export const splitProps = createSplitProps<Partial<UserDefinedContext>>(props) |
@@ -92,2 +92,6 @@ import type { StateMachine as S } from "@zag-js/core" | ||
/** | ||
* Whether the collapsible is visible (open or closing) | ||
*/ | ||
isVisible: boolean | ||
/** | ||
* Whether the collapsible is disabled | ||
@@ -94,0 +98,0 @@ */ |
export { anatomy } from "./collapsible.anatomy" | ||
export { connect } from "./collapsible.connect" | ||
export { machine } from "./collapsible.machine" | ||
export { props, splitProps } from "./collapsible.props" | ||
export type { | ||
@@ -5,0 +6,0 @@ MachineApi as Api, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
65974
970
+ Added@zag-js/anatomy@0.0.0-dev-20240222152205(transitive)
+ Added@zag-js/core@0.0.0-dev-20240222152205(transitive)
+ Added@zag-js/dom-query@0.0.0-dev-20240222152205(transitive)
+ Added@zag-js/store@0.0.0-dev-20240222152205(transitive)
+ Added@zag-js/types@0.0.0-dev-20240222152205(transitive)
+ Added@zag-js/utils@0.0.0-dev-20240222152205(transitive)
- Removed@zag-js/anatomy@0.0.0-dev-20240220140757(transitive)
- Removed@zag-js/core@0.0.0-dev-20240220140757(transitive)
- Removed@zag-js/dom-query@0.0.0-dev-20240220140757(transitive)
- Removed@zag-js/store@0.0.0-dev-20240220140757(transitive)
- Removed@zag-js/types@0.0.0-dev-20240220140757(transitive)
- Removed@zag-js/utils@0.0.0-dev-20240220140757(transitive)