@agnos-ui/core
Version:
Framework-agnostic headless component library.
254 lines (253 loc) • 8.22 kB
JavaScript
;
const tansu = require("@amadeus-it-group/tansu");
const utils_writables = require("./writables-Bn3uhKEG.cjs");
const utils_stores = require("./utils/stores.cjs");
const services_transitions_baseTransitions = require("./services/transitions/baseTransitions.cjs");
const promise = require("./promise-CxCD3NYv.cjs");
const utils_func = require("./utils/func.cjs");
const utils_directive = require("./dom-CuBx1JPZ.cjs");
const services_portal = require("./services/portal.cjs");
const services_siblingsInert = require("./services/siblingsInert.cjs");
const utils_widget = require("./utils/widget.cjs");
const internalRemoveScrollbars = () => {
const scrollbarWidth = Math.abs(window.innerWidth - document.documentElement.clientWidth);
const body = document.body;
const bodyStyle = body.style;
const { overflow, paddingRight } = bodyStyle;
if (scrollbarWidth > 0) {
const actualPadding = parseFloat(window.getComputedStyle(body).paddingRight);
bodyStyle.paddingRight = `${actualPadding + scrollbarWidth}px`;
}
bodyStyle.overflow = "hidden";
return () => {
if (scrollbarWidth > 0) {
bodyStyle.paddingRight = paddingRight;
}
bodyStyle.overflow = overflow;
};
};
let internalRevert = utils_func.noop;
const removeScrollbars = () => {
internalRevert();
internalRevert = internalRemoveScrollbars();
};
const revertScrollbars = () => {
internalRevert();
internalRevert = utils_func.noop;
};
const modalOutsideClick = Symbol();
const modalCloseButtonClick = Symbol();
const defaultConfig = {
animated: true,
ariaCloseButtonLabel: "Close",
backdrop: true,
backdropClass: "",
backdropTransition: utils_func.noop,
closeButton: true,
closeOnOutsideClick: true,
container: typeof window !== "undefined" ? document.body : null,
className: "",
modalTransition: utils_func.noop,
onBeforeClose: utils_func.noop,
onVisibleChange: utils_func.noop,
onHidden: utils_func.noop,
onShown: utils_func.noop,
visible: false
};
const configValidator = {
animated: utils_writables.typeBoolean,
ariaCloseButtonLabel: utils_writables.typeString,
backdrop: utils_writables.typeBoolean,
backdropClass: utils_writables.typeString,
backdropTransition: utils_writables.typeFunction,
closeButton: utils_writables.typeBoolean,
closeOnOutsideClick: utils_writables.typeBoolean,
container: utils_writables.typeHTMLElementOrNull,
className: utils_writables.typeString,
modalTransition: utils_writables.typeFunction,
onBeforeClose: utils_writables.typeFunction,
onVisibleChange: utils_writables.typeFunction,
onHidden: utils_writables.typeFunction,
onShown: utils_writables.typeFunction,
visible: utils_writables.typeBoolean
};
function getModalDefaultConfig() {
return { ...defaultConfig };
}
const modals$ = utils_directive.registrationArray();
const hasModals$ = tansu.computed(() => modals$().length > 0);
const scrollbarsAction$ = tansu.computed(() => {
if (hasModals$()) {
removeScrollbars();
} else {
revertScrollbars();
}
});
const modalsAction$ = tansu.computed(() => {
scrollbarsAction$();
});
const createModal = utils_widget.createWidgetFactory("modal", (config$) => {
const [
{
animated$,
backdrop$,
backdropTransition$,
closeOnOutsideClick$,
container$,
modalTransition$,
onBeforeClose$,
onVisibleChange$,
onHidden$,
onShown$,
ariaCloseButtonLabel$,
className$,
backdropClass$,
visible$: requestedVisible$,
...stateProps
},
patch
] = utils_stores.writablesForProps(defaultConfig, config$, configValidator);
const modalTransition = services_transitions_baseTransitions.createTransition({
props: {
transition: modalTransition$,
visible: requestedVisible$,
animated: animated$,
animatedOnInit: animated$,
onVisibleChange: onVisibleChange$,
// TODO: for onHidden and onShown, should we combine with information from the backdrop transition?
// (especially in case one of the two transitions takes more time than the other)
onHidden: onHidden$,
onShown: onShown$
}
});
const visible$ = modalTransition.stores.visible$;
const backdropTransition = services_transitions_baseTransitions.createTransition({
props: {
transition: backdropTransition$,
visible: requestedVisible$,
animated: animated$,
animatedOnInit: animated$
}
});
const transitioning$ = tansu.computed(() => modalTransition.stores.transitioning$() || backdrop$() && backdropTransition.stores.transitioning$());
const hidden$ = tansu.computed(() => !transitioning$() && !visible$());
const backdropHidden$ = tansu.computed(() => !backdrop$() || hidden$());
let hideResult;
const close = (result) => {
hideResult = result;
const beforeCloseEvent = {
get result() {
return hideResult;
},
set result(value) {
hideResult = value;
},
cancel: false
};
onBeforeClose$()(beforeCloseEvent);
if (beforeCloseEvent.cancel) {
return;
}
patch({ visible: false });
};
const modalPortalDirective = utils_directive.bindDirective(
services_portal.portal,
tansu.computed(() => ({ container: container$() }))
);
const backdropPortalDirective = utils_directive.bindDirective(
services_portal.portal,
tansu.computed(() => {
const container = container$();
const element = container ? modalTransition.stores.element$() : void 0;
return {
container,
insertBefore: (element == null ? void 0 : element.parentElement) === container ? element : void 0
};
})
);
const registerModalAction$ = tansu.readable(void 0, () => modals$.register(res));
const action$ = tansu.computed(() => {
if (modalTransition.stores.elementPresent$() && !hidden$()) {
registerModalAction$();
}
modalsAction$();
});
const closeButtonDirective = utils_directive.createAttributesDirective(() => ({
attributes: {
type: tansu.readable("button"),
"aria-label": ariaCloseButtonLabel$
},
events: {
click: () => close(modalCloseButtonClick)
}
}));
const backdropAttributeDirective = utils_directive.createAttributesDirective(() => ({
attributes: {
class: backdropClass$
}
}));
const modalAttributeDirective = utils_directive.createAttributesDirective(() => ({
attributes: {
class: className$
},
events: {
click: (event) => {
if (event.currentTarget === event.target && closeOnOutsideClick$()) {
close(modalOutsideClick);
}
}
}
}));
const res = {
...utils_stores.stateStores({
backdropHidden$,
container$,
hidden$,
transitioning$,
visible$,
modalElement$: modalTransition.stores.element$,
ariaCloseButtonLabel$,
className$,
backdropClass$,
...stateProps
}),
directives: {
modalPortalDirective,
backdropPortalDirective,
backdropDirective: utils_directive.mergeDirectives(backdropTransition.directives.directive, backdropAttributeDirective),
modalDirective: utils_directive.mergeDirectives(modalTransition.directives.directive, services_siblingsInert.siblingsInert, utils_directive.directiveSubscribe(action$), modalAttributeDirective),
closeButtonDirective,
dialogDirective: utils_directive.bindDirective(
utils_directive.browserDirective((dialog, visible) => {
const update = (visible2) => {
if (visible2) {
dialog.showModal();
} else {
dialog.close();
}
};
update(visible);
return {
update
};
}),
visible$
)
},
patch,
api: {
close,
async open() {
patch({ visible: true });
await promise.promiseFromStore(hidden$).promise;
return hideResult;
},
patch
}
};
return res;
});
exports.createModal = createModal;
exports.getModalDefaultConfig = getModalDefaultConfig;
exports.modalCloseButtonClick = modalCloseButtonClick;
exports.modalOutsideClick = modalOutsideClick;