@cgi-learning-hub/ui
Version:
@cgi-learning-hub/ui is an open-source React component library that implements UI for HUB's features
745 lines (744 loc) • 24 kB
JavaScript
import * as u from "react";
import { P as n } from "./index-B9vkf41S.js";
import { F as me, G as be, H as J } from "./generateUtilityClasses-B_xKAflz.js";
import { m as he } from "./memoTheme-C-PaH-Cy.js";
import { o as H } from "./ownerWindow-niciwP7I.js";
import { o as O } from "./ownerDocument-CUrv0DIK.js";
import { u as re } from "./useForkRef-u29GSuCu.js";
import { a as Q } from "./useEventCallback-Y2KwRxBw.js";
import { c as Z } from "./createChainedFunction-C0nujS3O.js";
import { e as ge, u as ee } from "./useSlot-BSkdRaZr.js";
import { jsxs as se, jsx as j } from "react/jsx-runtime";
import { u as Ee, s as ie, c as Te } from "./DefaultPropsProvider-BrmlvPWg.js";
import { e as ye, P as xe, H as Re } from "./Portal-PkRJuFYN.js";
import { g as Pe, e as ae } from "./elementAcceptingRef-CZLfau9O.js";
import { B as ve } from "./Backdrop-BvL371G3.js";
function ke(e = window) {
const t = e.document.documentElement.clientWidth;
return e.innerWidth - t;
}
function Ie(e) {
const t = O(e);
return t.body === e ? H(e).innerWidth > t.documentElement.clientWidth : e.scrollHeight > e.clientHeight;
}
function K(e, t) {
t ? e.setAttribute("aria-hidden", "true") : e.removeAttribute("aria-hidden");
}
function te(e) {
return parseInt(H(e).getComputedStyle(e).paddingRight, 10) || 0;
}
function Ne(e) {
const s = ["TEMPLATE", "SCRIPT", "STYLE", "LINK", "MAP", "META", "NOSCRIPT", "PICTURE", "COL", "COLGROUP", "PARAM", "SLOT", "SOURCE", "TRACK"].includes(e.tagName), o = e.tagName === "INPUT" && e.getAttribute("type") === "hidden";
return s || o;
}
function oe(e, t, s, o, i) {
const r = [t, s, ...o];
[].forEach.call(e.children, (a) => {
const c = !r.includes(a), m = !Ne(a);
c && m && K(a, i);
});
}
function Y(e, t) {
let s = -1;
return e.some((o, i) => t(o) ? (s = i, !0) : !1), s;
}
function Fe(e, t) {
const s = [], o = e.container;
if (!t.disableScrollLock) {
if (Ie(o)) {
const a = ke(H(o));
s.push({
value: o.style.paddingRight,
property: "padding-right",
el: o
}), o.style.paddingRight = `${te(o) + a}px`;
const c = O(o).querySelectorAll(".mui-fixed");
[].forEach.call(c, (m) => {
s.push({
value: m.style.paddingRight,
property: "padding-right",
el: m
}), m.style.paddingRight = `${te(m) + a}px`;
});
}
let r;
if (o.parentNode instanceof DocumentFragment)
r = O(o).body;
else {
const a = o.parentElement, c = H(o);
r = (a == null ? void 0 : a.nodeName) === "HTML" && c.getComputedStyle(a).overflowY === "scroll" ? a : o;
}
s.push({
value: r.style.overflow,
property: "overflow",
el: r
}, {
value: r.style.overflowX,
property: "overflow-x",
el: r
}, {
value: r.style.overflowY,
property: "overflow-y",
el: r
}), r.style.overflow = "hidden";
}
return () => {
s.forEach(({
value: r,
el: a,
property: c
}) => {
r ? a.style.setProperty(c, r) : a.style.removeProperty(c);
});
};
}
function Se(e) {
const t = [];
return [].forEach.call(e.children, (s) => {
s.getAttribute("aria-hidden") === "true" && t.push(s);
}), t;
}
class Ce {
constructor() {
this.modals = [], this.containers = [];
}
add(t, s) {
let o = this.modals.indexOf(t);
if (o !== -1)
return o;
o = this.modals.length, this.modals.push(t), t.modalRef && K(t.modalRef, !1);
const i = Se(s);
oe(s, t.mount, t.modalRef, i, !0);
const r = Y(this.containers, (a) => a.container === s);
return r !== -1 ? (this.containers[r].modals.push(t), o) : (this.containers.push({
modals: [t],
container: s,
restore: null,
hiddenSiblings: i
}), o);
}
mount(t, s) {
const o = Y(this.containers, (r) => r.modals.includes(t)), i = this.containers[o];
i.restore || (i.restore = Fe(i, s));
}
remove(t, s = !0) {
const o = this.modals.indexOf(t);
if (o === -1)
return o;
const i = Y(this.containers, (a) => a.modals.includes(t)), r = this.containers[i];
if (r.modals.splice(r.modals.indexOf(t), 1), this.modals.splice(o, 1), r.modals.length === 0)
r.restore && r.restore(), t.modalRef && K(t.modalRef, s), oe(r.container, t.mount, t.modalRef, r.hiddenSiblings, !1), this.containers.splice(i, 1);
else {
const a = r.modals[r.modals.length - 1];
a.modalRef && K(a.modalRef, !1);
}
return o;
}
isTopModal(t) {
return this.modals.length > 0 && this.modals[this.modals.length - 1] === t;
}
}
const Me = ["input", "select", "textarea", "a[href]", "button", "[tabindex]", "audio[controls]", "video[controls]", '[contenteditable]:not([contenteditable="false"])'].join(",");
function we(e) {
const t = parseInt(e.getAttribute("tabindex") || "", 10);
return Number.isNaN(t) ? e.contentEditable === "true" || (e.nodeName === "AUDIO" || e.nodeName === "VIDEO" || e.nodeName === "DETAILS") && e.getAttribute("tabindex") === null ? 0 : e.tabIndex : t;
}
function Oe(e) {
if (e.tagName !== "INPUT" || e.type !== "radio" || !e.name)
return !1;
const t = (o) => e.ownerDocument.querySelector(`input[type="radio"]${o}`);
let s = t(`[name="${e.name}"]:checked`);
return s || (s = t(`[name="${e.name}"]`)), s !== e;
}
function Ae(e) {
return !(e.disabled || e.tagName === "INPUT" && e.type === "hidden" || Oe(e));
}
function De(e) {
const t = [], s = [];
return Array.from(e.querySelectorAll(Me)).forEach((o, i) => {
const r = we(o);
r === -1 || !Ae(o) || (r === 0 ? t.push(o) : s.push({
documentOrder: i,
tabIndex: r,
node: o
}));
}), s.sort((o, i) => o.tabIndex === i.tabIndex ? o.documentOrder - i.documentOrder : o.tabIndex - i.tabIndex).map((o) => o.node).concat(t);
}
function Le() {
return !0;
}
function z(e) {
const {
children: t,
disableAutoFocus: s = !1,
disableEnforceFocus: o = !1,
disableRestoreFocus: i = !1,
getTabbable: r = De,
isEnabled: a = Le,
open: c
} = e, m = u.useRef(!1), E = u.useRef(null), v = u.useRef(null), h = u.useRef(null), y = u.useRef(null), b = u.useRef(!1), p = u.useRef(null), M = re(Pe(t), p), N = u.useRef(null);
u.useEffect(() => {
!c || !p.current || (b.current = !s);
}, [s, c]), u.useEffect(() => {
if (!c || !p.current)
return;
const l = O(p.current);
return p.current.contains(l.activeElement) || (p.current.hasAttribute("tabIndex") || (process.env.NODE_ENV !== "production" && console.error(["MUI: The modal content node does not accept focus.", 'For the benefit of assistive technologies, the tabIndex of the node is being set to "-1".'].join(`
`)), p.current.setAttribute("tabIndex", "-1")), b.current && p.current.focus()), () => {
i || (h.current && h.current.focus && (m.current = !0, h.current.focus()), h.current = null);
};
}, [c]), u.useEffect(() => {
if (!c || !p.current)
return;
const l = O(p.current), g = (T) => {
N.current = T, !(o || !a() || T.key !== "Tab") && l.activeElement === p.current && T.shiftKey && (m.current = !0, v.current && v.current.focus());
}, k = () => {
var x, w;
const T = p.current;
if (T === null)
return;
if (!l.hasFocus() || !a() || m.current) {
m.current = !1;
return;
}
if (T.contains(l.activeElement) || o && l.activeElement !== E.current && l.activeElement !== v.current)
return;
if (l.activeElement !== y.current)
y.current = null;
else if (y.current !== null)
return;
if (!b.current)
return;
let S = [];
if ((l.activeElement === E.current || l.activeElement === v.current) && (S = r(p.current)), S.length > 0) {
const D = !!((x = N.current) != null && x.shiftKey && ((w = N.current) == null ? void 0 : w.key) === "Tab"), U = S[0], L = S[S.length - 1];
typeof U != "string" && typeof L != "string" && (D ? L.focus() : U.focus());
} else
T.focus();
};
l.addEventListener("focusin", k), l.addEventListener("keydown", g, !0);
const A = setInterval(() => {
l.activeElement && l.activeElement.tagName === "BODY" && k();
}, 50);
return () => {
clearInterval(A), l.removeEventListener("focusin", k), l.removeEventListener("keydown", g, !0);
};
}, [s, o, i, a, c, r]);
const F = (l) => {
h.current === null && (h.current = l.relatedTarget), b.current = !0, y.current = l.target;
const g = t.props.onFocus;
g && g(l);
}, R = (l) => {
h.current === null && (h.current = l.relatedTarget), b.current = !0;
};
return /* @__PURE__ */ se(u.Fragment, {
children: [/* @__PURE__ */ j("div", {
tabIndex: c ? 0 : -1,
onFocus: R,
ref: E,
"data-testid": "sentinelStart"
}), /* @__PURE__ */ u.cloneElement(t, {
ref: M,
onFocus: F
}), /* @__PURE__ */ j("div", {
tabIndex: c ? 0 : -1,
onFocus: R,
ref: v,
"data-testid": "sentinelEnd"
})]
});
}
process.env.NODE_ENV !== "production" && (z.propTypes = {
// ┌────────────────────────────── Warning ──────────────────────────────┐
// │ These PropTypes are generated from the TypeScript type definitions. │
// │ To update them, edit the TypeScript types and run `pnpm proptypes`. │
// └─────────────────────────────────────────────────────────────────────┘
/**
* A single child content element.
*/
children: ae,
/**
* If `true`, the focus trap will not automatically shift focus to itself when it opens, and
* replace it to the last focused element when it closes.
* This also works correctly with any focus trap children that have the `disableAutoFocus` prop.
*
* Generally this should never be set to `true` as it makes the focus trap less
* accessible to assistive technologies, like screen readers.
* @default false
*/
disableAutoFocus: n.bool,
/**
* If `true`, the focus trap will not prevent focus from leaving the focus trap while open.
*
* Generally this should never be set to `true` as it makes the focus trap less
* accessible to assistive technologies, like screen readers.
* @default false
*/
disableEnforceFocus: n.bool,
/**
* If `true`, the focus trap will not restore focus to previously focused element once
* focus trap is hidden or unmounted.
* @default false
*/
disableRestoreFocus: n.bool,
/**
* Returns an array of ordered tabbable nodes (i.e. in tab order) within the root.
* For instance, you can provide the "tabbable" npm dependency.
* @param {HTMLElement} root
*/
getTabbable: n.func,
/**
* This prop extends the `open` prop.
* It allows to toggle the open state without having to wait for a rerender when changing the `open` prop.
* This prop should be memoized.
* It can be used to support multiple focus trap mounted at the same time.
* @default function defaultIsEnabled(): boolean {
* return true;
* }
*/
isEnabled: n.func,
/**
* If `true`, focus is locked.
*/
open: n.bool.isRequired
});
process.env.NODE_ENV !== "production" && (z.propTypes = ye(z.propTypes));
function Be(e) {
return typeof e == "function" ? e() : e;
}
function je(e) {
return e ? e.props.hasOwnProperty("in") : !1;
}
const ne = () => {
}, q = new Ce();
function Ke(e) {
const {
container: t,
disableEscapeKeyDown: s = !1,
disableScrollLock: o = !1,
closeAfterTransition: i = !1,
onTransitionEnter: r,
onTransitionExited: a,
children: c,
onClose: m,
open: E,
rootRef: v
} = e, h = u.useRef({}), y = u.useRef(null), b = u.useRef(null), p = re(b, v), [M, N] = u.useState(!E), F = je(c);
let R = !0;
(e["aria-hidden"] === "false" || e["aria-hidden"] === !1) && (R = !1);
const l = () => O(y.current), g = () => (h.current.modalRef = b.current, h.current.mount = y.current, h.current), k = () => {
q.mount(g(), {
disableScrollLock: o
}), b.current && (b.current.scrollTop = 0);
}, A = Q(() => {
const f = Be(t) || l().body;
q.add(g(), f), b.current && k();
}), T = () => q.isTopModal(g()), S = Q((f) => {
y.current = f, f && (E && T() ? k() : b.current && K(b.current, R));
}), x = u.useCallback(() => {
q.remove(g(), R);
}, [R]);
u.useEffect(() => () => {
x();
}, [x]), u.useEffect(() => {
E ? A() : (!F || !i) && x();
}, [E, x, F, i, A]);
const w = (f) => (d) => {
var P;
(P = f.onKeyDown) == null || P.call(f, d), !(d.key !== "Escape" || d.which === 229 || // Wait until IME is settled.
!T()) && (s || (d.stopPropagation(), m && m(d, "escapeKeyDown")));
}, D = (f) => (d) => {
var P;
(P = f.onClick) == null || P.call(f, d), d.target === d.currentTarget && m && m(d, "backdropClick");
};
return {
getRootProps: (f = {}) => {
const d = ge(e);
delete d.onTransitionEnter, delete d.onTransitionExited;
const P = {
...d,
...f
};
return {
/*
* Marking an element with the role presentation indicates to assistive technology
* that this element should be ignored; it exists to support the web application and
* is not meant for humans to interact with directly.
* https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-static-element-interactions.md
*/
role: "presentation",
...P,
onKeyDown: w(P),
ref: p
};
},
getBackdropProps: (f = {}) => {
const d = f;
return {
"aria-hidden": !0,
...d,
onClick: D(d),
open: E
};
},
getTransitionProps: () => {
const f = () => {
N(!1), r && r();
}, d = () => {
N(!0), a && a(), i && x();
};
return {
onEnter: Z(f, (c == null ? void 0 : c.props.onEnter) ?? ne),
onExited: Z(d, (c == null ? void 0 : c.props.onExited) ?? ne)
};
},
rootRef: p,
portalRef: S,
isTopModal: T,
exited: M,
hasTransition: F
};
}
function Ue(e) {
return be("MuiModal", e);
}
const st = me("MuiModal", ["root", "hidden", "backdrop"]), We = (e) => {
const {
open: t,
exited: s,
classes: o
} = e;
return Te({
root: ["root", !t && s && "hidden"],
backdrop: ["backdrop"]
}, Ue, o);
}, qe = ie("div", {
name: "MuiModal",
slot: "Root",
overridesResolver: (e, t) => {
const {
ownerState: s
} = e;
return [t.root, !s.open && s.exited && t.hidden];
}
})(he(({
theme: e
}) => ({
position: "fixed",
zIndex: (e.vars || e).zIndex.modal,
right: 0,
bottom: 0,
top: 0,
left: 0,
variants: [{
props: ({
ownerState: t
}) => !t.open && t.exited,
style: {
visibility: "hidden"
}
}]
}))), He = ie(ve, {
name: "MuiModal",
slot: "Backdrop"
})({
zIndex: -1
}), ze = /* @__PURE__ */ u.forwardRef(function(t, s) {
const o = Ee({
name: "MuiModal",
props: t
}), {
BackdropComponent: i = He,
BackdropProps: r,
classes: a,
className: c,
closeAfterTransition: m = !1,
children: E,
container: v,
component: h,
components: y = {},
componentsProps: b = {},
disableAutoFocus: p = !1,
disableEnforceFocus: M = !1,
disableEscapeKeyDown: N = !1,
disablePortal: F = !1,
disableRestoreFocus: R = !1,
disableScrollLock: l = !1,
hideBackdrop: g = !1,
keepMounted: k = !1,
onClose: A,
onTransitionEnter: T,
onTransitionExited: S,
open: x,
slotProps: w = {},
slots: D = {},
// eslint-disable-next-line react/prop-types
theme: U,
...L
} = o, V = {
...o,
closeAfterTransition: m,
disableAutoFocus: p,
disableEnforceFocus: M,
disableEscapeKeyDown: N,
disablePortal: F,
disableRestoreFocus: R,
disableScrollLock: l,
hideBackdrop: g,
keepMounted: k
}, {
getRootProps: f,
getBackdropProps: d,
getTransitionProps: P,
portalRef: ce,
isTopModal: le,
exited: _,
hasTransition: G
} = Ke({
...V,
rootRef: s
}), B = {
...V,
exited: _
}, I = We(B), W = {};
if (E.props.tabIndex === void 0 && (W.tabIndex = "-1"), G) {
const {
onEnter: C,
onExited: $
} = P();
W.onEnter = C, W.onExited = $;
}
const X = {
slots: {
root: y.Root,
backdrop: y.Backdrop,
...D
},
slotProps: {
...b,
...w
}
}, [ue, de] = ee("root", {
ref: s,
elementType: qe,
externalForwardedProps: {
...X,
...L,
component: h
},
getSlotProps: f,
ownerState: B,
className: J(c, I == null ? void 0 : I.root, !B.open && B.exited && (I == null ? void 0 : I.hidden))
}), [fe, pe] = ee("backdrop", {
ref: r == null ? void 0 : r.ref,
elementType: i,
externalForwardedProps: X,
shouldForwardComponentProp: !0,
additionalProps: r,
getSlotProps: (C) => d({
...C,
onClick: ($) => {
C != null && C.onClick && C.onClick($);
}
}),
className: J(r == null ? void 0 : r.className, I == null ? void 0 : I.backdrop),
ownerState: B
});
return !k && !x && (!G || _) ? null : /* @__PURE__ */ j(xe, {
ref: ce,
container: v,
disablePortal: F,
children: /* @__PURE__ */ se(ue, {
...de,
children: [!g && i ? /* @__PURE__ */ j(fe, {
...pe
}) : null, /* @__PURE__ */ j(z, {
disableEnforceFocus: M,
disableAutoFocus: p,
disableRestoreFocus: R,
isEnabled: le,
open: x,
children: /* @__PURE__ */ u.cloneElement(E, W)
})]
})
});
});
process.env.NODE_ENV !== "production" && (ze.propTypes = {
// ┌────────────────────────────── Warning ──────────────────────────────┐
// │ These PropTypes are generated from the TypeScript type definitions. │
// │ To update them, edit the d.ts file and run `pnpm proptypes`. │
// └─────────────────────────────────────────────────────────────────────┘
/**
* A backdrop component. This prop enables custom backdrop rendering.
* @deprecated Use `slots.backdrop` instead. While this prop currently works, it will be removed in the next major version.
* Use the `slots.backdrop` prop to make your application ready for the next version of Material UI.
* @default styled(Backdrop, {
* name: 'MuiModal',
* slot: 'Backdrop',
* })({
* zIndex: -1,
* })
*/
BackdropComponent: n.elementType,
/**
* Props applied to the [`Backdrop`](https://mui.com/material-ui/api/backdrop/) element.
* @deprecated Use `slotProps.backdrop` instead.
*/
BackdropProps: n.object,
/**
* A single child content element.
*/
children: ae.isRequired,
/**
* Override or extend the styles applied to the component.
*/
classes: n.object,
/**
* @ignore
*/
className: n.string,
/**
* When set to true the Modal waits until a nested Transition is completed before closing.
* @default false
*/
closeAfterTransition: n.bool,
/**
* The component used for the root node.
* Either a string to use a HTML element or a component.
*/
component: n.elementType,
/**
* The components used for each slot inside.
*
* @deprecated Use the `slots` prop instead. This prop will be removed in a future major release. See [Migrating from deprecated APIs](https://mui.com/material-ui/migration/migrating-from-deprecated-apis/) for more details.
*
* @default {}
*/
components: n.shape({
Backdrop: n.elementType,
Root: n.elementType
}),
/**
* The extra props for the slot components.
* You can override the existing props or add new ones.
*
* @deprecated Use the `slotProps` prop instead. This prop will be removed in a future major release. See [Migrating from deprecated APIs](https://mui.com/material-ui/migration/migrating-from-deprecated-apis/) for more details.
*
* @default {}
*/
componentsProps: n.shape({
backdrop: n.oneOfType([n.func, n.object]),
root: n.oneOfType([n.func, n.object])
}),
/**
* An HTML element or function that returns one.
* The `container` will have the portal children appended to it.
*
* You can also provide a callback, which is called in a React layout effect.
* This lets you set the container from a ref, and also makes server-side rendering possible.
*
* By default, it uses the body of the top-level document object,
* so it's simply `document.body` most of the time.
*/
container: n.oneOfType([Re, n.func]),
/**
* If `true`, the modal will not automatically shift focus to itself when it opens, and
* replace it to the last focused element when it closes.
* This also works correctly with any modal children that have the `disableAutoFocus` prop.
*
* Generally this should never be set to `true` as it makes the modal less
* accessible to assistive technologies, like screen readers.
* @default false
*/
disableAutoFocus: n.bool,
/**
* If `true`, the modal will not prevent focus from leaving the modal while open.
*
* Generally this should never be set to `true` as it makes the modal less
* accessible to assistive technologies, like screen readers.
* @default false
*/
disableEnforceFocus: n.bool,
/**
* If `true`, hitting escape will not fire the `onClose` callback.
* @default false
*/
disableEscapeKeyDown: n.bool,
/**
* The `children` will be under the DOM hierarchy of the parent component.
* @default false
*/
disablePortal: n.bool,
/**
* If `true`, the modal will not restore focus to previously focused element once
* modal is hidden or unmounted.
* @default false
*/
disableRestoreFocus: n.bool,
/**
* Disable the scroll lock behavior.
* @default false
*/
disableScrollLock: n.bool,
/**
* If `true`, the backdrop is not rendered.
* @default false
*/
hideBackdrop: n.bool,
/**
* Always keep the children in the DOM.
* This prop can be useful in SEO situation or
* when you want to maximize the responsiveness of the Modal.
* @default false
*/
keepMounted: n.bool,
/**
* Callback fired when the component requests to be closed.
* The `reason` parameter can optionally be used to control the response to `onClose`.
*
* @param {object} event The event source of the callback.
* @param {string} reason Can be: `"escapeKeyDown"`, `"backdropClick"`.
*/
onClose: n.func,
/**
* A function called when a transition enters.
*/
onTransitionEnter: n.func,
/**
* A function called when a transition has exited.
*/
onTransitionExited: n.func,
/**
* If `true`, the component is shown.
*/
open: n.bool.isRequired,
/**
* The props used for each slot inside the Modal.
* @default {}
*/
slotProps: n.shape({
backdrop: n.oneOfType([n.func, n.object]),
root: n.oneOfType([n.func, n.object])
}),
/**
* The components used for each slot inside the Modal.
* Either a string to use a HTML element or a component.
* @default {}
*/
slots: n.shape({
backdrop: n.elementType,
root: n.elementType
}),
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx: n.oneOfType([n.arrayOf(n.oneOfType([n.func, n.object, n.bool])), n.func, n.object])
});
export {
z as F,
ze as M,
Ce as a,
ke as b,
Ue as g,
st as m
};