@cuemath/leap 3.1.5 → 3.1.6-gg2
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/dist/features/ui/modals/modal-context.js +13 -0
- package/dist/features/ui/modals/modal-context.js.map +1 -0
- package/dist/features/ui/modals/modal-helpers.js +17 -0
- package/dist/features/ui/modals/modal-helpers.js.map +1 -0
- package/dist/features/ui/modals/modal-provider.js +48 -0
- package/dist/features/ui/modals/modal-provider.js.map +1 -0
- package/dist/features/ui/modals/modal-styled.js +154 -0
- package/dist/features/ui/modals/modal-styled.js.map +1 -0
- package/dist/features/ui/modals/modal.js +19 -0
- package/dist/features/ui/modals/modal.js.map +1 -0
- package/dist/features/ui/modals/use-modal-actions.js +10 -0
- package/dist/features/ui/modals/use-modal-actions.js.map +1 -0
- package/dist/features/ui/modals/use-modal-params.js +10 -0
- package/dist/features/ui/modals/use-modal-params.js.map +1 -0
- package/dist/index.d.ts +56 -0
- package/dist/index.js +339 -333
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"modal-context.js","sources":["../../../../src/features/ui/modals/modal-context.ts"],"sourcesContent":["import type { IModalContext } from './modal-types';\n\nimport { createContext } from 'react';\n\n/**\n * Context for providing modal functionality throughout the application\n * Provides access to modal state and actions to open/close modals\n *\n * @example\n * // Usage with useContext\n * const { openModal, closeModal } = useContext(ModalContext);\n * openModal('modalName', { someParam: 'value' });\n */\nconst ModalContext = createContext<IModalContext>({\n modal: null,\n openModal: () => {},\n closeModal: () => {},\n isClosing: false,\n});\n\nexport default ModalContext;\n"],"names":["ModalContext","createContext"],"mappings":";AAaA,MAAMA,IAAeC,EAA6B;AAAA,EAChD,OAAO;AAAA,EACP,WAAW,MAAM;AAAA,EAAC;AAAA,EAClB,YAAY,MAAM;AAAA,EAAC;AAAA,EACnB,WAAW;AACb,CAAC;"}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
const e = () => {
|
2
|
+
const o = window.innerWidth > document.documentElement.clientWidth;
|
3
|
+
if (document.body.dataset.originalOverflow = document.body.style.overflow || "", o) {
|
4
|
+
const d = window.innerWidth - document.documentElement.clientWidth;
|
5
|
+
document.body.dataset.originalPadding = document.body.style.paddingRight || "";
|
6
|
+
const t = parseInt(window.getComputedStyle(document.body).paddingRight, 10) || 0;
|
7
|
+
document.body.style.paddingRight = `${t + d}px`;
|
8
|
+
}
|
9
|
+
document.body.style.overflow = "hidden", document.body.style.touchAction = "none";
|
10
|
+
}, n = () => {
|
11
|
+
document.body.dataset.originalPadding !== void 0 && (document.body.style.paddingRight = document.body.dataset.originalPadding, delete document.body.dataset.originalPadding), document.body.dataset.originalOverflow !== void 0 ? (document.body.style.overflow = document.body.dataset.originalOverflow, delete document.body.dataset.originalOverflow) : document.body.style.overflow = "", document.body.style.touchAction = "";
|
12
|
+
};
|
13
|
+
export {
|
14
|
+
e as lockScroll,
|
15
|
+
n as unlockScroll
|
16
|
+
};
|
17
|
+
//# sourceMappingURL=modal-helpers.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"modal-helpers.js","sources":["../../../../src/features/ui/modals/modal-helpers.ts"],"sourcesContent":["/**\n * Locks scrolling on the body element while preserving the scrollbar width to prevent layout shifts.\n * Stores original style values in data attributes for later restoration.\n */\nexport const lockScroll = (): void => {\n // Calculate if scrollbar is present\n const hasScrollbar = window.innerWidth > document.documentElement.clientWidth;\n\n // Save original overflow state regardless\n document.body.dataset.originalOverflow = document.body.style.overflow || '';\n\n if (hasScrollbar) {\n // Calculate scrollbar width\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n\n // Save original padding\n document.body.dataset.originalPadding = document.body.style.paddingRight || '';\n\n // Get current padding if any\n const currentPadding = parseInt(window.getComputedStyle(document.body).paddingRight, 10) || 0;\n\n // Add padding to prevent content shift when scrollbar disappears\n document.body.style.paddingRight = `${currentPadding + scrollbarWidth}px`;\n }\n\n // Lock scroll\n document.body.style.overflow = 'hidden';\n document.body.style.touchAction = 'none'; // Prevent touch scrolling on mobile\n};\n\n/**\n * Unlocks scrolling on the body element and restores original styles.\n * Uses stored data attributes from lockScroll to restore previous state.\n */\nexport const unlockScroll = (): void => {\n // Restore original padding if it was set\n if (document.body.dataset.originalPadding !== undefined) {\n document.body.style.paddingRight = document.body.dataset.originalPadding;\n delete document.body.dataset.originalPadding;\n }\n\n // Restore original overflow\n if (document.body.dataset.originalOverflow !== undefined) {\n document.body.style.overflow = document.body.dataset.originalOverflow;\n delete document.body.dataset.originalOverflow;\n } else {\n document.body.style.overflow = '';\n }\n\n document.body.style.touchAction = '';\n};\n"],"names":["lockScroll","hasScrollbar","scrollbarWidth","currentPadding","unlockScroll"],"mappings":"AAIO,MAAMA,IAAa,MAAY;AAEpC,QAAMC,IAAe,OAAO,aAAa,SAAS,gBAAgB;AAKlE,MAFA,SAAS,KAAK,QAAQ,mBAAmB,SAAS,KAAK,MAAM,YAAY,IAErEA,GAAc;AAEhB,UAAMC,IAAiB,OAAO,aAAa,SAAS,gBAAgB;AAGpE,aAAS,KAAK,QAAQ,kBAAkB,SAAS,KAAK,MAAM,gBAAgB;AAGtE,UAAAC,IAAiB,SAAS,OAAO,iBAAiB,SAAS,IAAI,EAAE,cAAc,EAAE,KAAK;AAG5F,aAAS,KAAK,MAAM,eAAe,GAAGA,IAAiBD,CAAc;AAAA,EACvE;AAGS,WAAA,KAAK,MAAM,WAAW,UACtB,SAAA,KAAK,MAAM,cAAc;AACpC,GAMaE,IAAe,MAAY;AAEtC,EAAI,SAAS,KAAK,QAAQ,oBAAoB,WAC5C,SAAS,KAAK,MAAM,eAAe,SAAS,KAAK,QAAQ,iBAClD,OAAA,SAAS,KAAK,QAAQ,kBAI3B,SAAS,KAAK,QAAQ,qBAAqB,UAC7C,SAAS,KAAK,MAAM,WAAW,SAAS,KAAK,QAAQ,kBAC9C,OAAA,SAAS,KAAK,QAAQ,oBAEpB,SAAA,KAAK,MAAM,WAAW,IAGxB,SAAA,KAAK,MAAM,cAAc;AACpC;"}
|
@@ -0,0 +1,48 @@
|
|
1
|
+
import { jsxs as k, jsx as C } from "react/jsx-runtime";
|
2
|
+
import { memo as E, useState as a, useCallback as M, useMemo as x, useEffect as u } from "react";
|
3
|
+
import y from "./modal.js";
|
4
|
+
import I from "./modal-context.js";
|
5
|
+
import { lockScroll as S, unlockScroll as h } from "./modal-helpers.js";
|
6
|
+
const D = 500, T = E(({ children: w, modals: d, isUserAuthenticated: t }) => {
|
7
|
+
const [o, c] = a(null), [f, v] = a(void 0), [s, r] = a(!1), m = M(
|
8
|
+
(n, l) => {
|
9
|
+
const i = d.find((P) => P.name === n);
|
10
|
+
if (!i)
|
11
|
+
throw new Error(`Modal with name "${n}" not found`);
|
12
|
+
if (i.isPrivate && !t)
|
13
|
+
throw new Error(
|
14
|
+
`Access violation: Modal "${n}" is private and user is not authenticated`
|
15
|
+
);
|
16
|
+
r(!1), c(i), v(l), S();
|
17
|
+
},
|
18
|
+
[t, d]
|
19
|
+
), e = M(() => {
|
20
|
+
r(!0), h(), setTimeout(() => {
|
21
|
+
c(null), r(!1);
|
22
|
+
}, D);
|
23
|
+
}, []), p = x(
|
24
|
+
() => ({
|
25
|
+
modal: o,
|
26
|
+
modalParams: f,
|
27
|
+
openModal: m,
|
28
|
+
closeModal: e,
|
29
|
+
isClosing: s
|
30
|
+
}),
|
31
|
+
[o, f, m, e, s]
|
32
|
+
);
|
33
|
+
return u(() => {
|
34
|
+
!t && (o != null && o.isPrivate) && e();
|
35
|
+
}, [t, o, e]), u(() => {
|
36
|
+
const n = (l) => {
|
37
|
+
l.key === "Escape" && (o == null ? void 0 : o.isDismissable) !== !1 && !s && e();
|
38
|
+
};
|
39
|
+
return window.addEventListener("keydown", n), () => window.removeEventListener("keydown", n);
|
40
|
+
}, [o, e, s]), /* @__PURE__ */ k(I.Provider, { value: p, children: [
|
41
|
+
w,
|
42
|
+
o && /* @__PURE__ */ C(y, { modal: o, isClosing: s, onClose: e })
|
43
|
+
] });
|
44
|
+
}), O = T;
|
45
|
+
export {
|
46
|
+
O as default
|
47
|
+
};
|
48
|
+
//# sourceMappingURL=modal-provider.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"modal-provider.js","sources":["../../../../src/features/ui/modals/modal-provider.tsx"],"sourcesContent":["import type { IModal, IModalContext, IModalProviderProps } from './modal-types';\nimport type { FC } from 'react';\n\nimport { memo, useCallback, useEffect, useMemo, useState } from 'react';\n\nimport Modal from './modal';\nimport ModalContext from './modal-context';\nimport { lockScroll, unlockScroll } from './modal-helpers';\n\nconst ANIMATION_DURATION_MS = 500; // Match the animation duration in modal.tsx\n\n/**\n * Provider component that manages modal state and provides modal context to child components\n */\nconst ModalProvider: FC<IModalProviderProps> = memo(({ children, modals, isUserAuthenticated }) => {\n const [modal, setModal] = useState<IModal | null>(null);\n const [modalParams, setModalParams] = useState<Record<string, unknown> | undefined>(undefined);\n const [isClosing, setIsClosing] = useState(false);\n\n /**\n * Opens a modal by name with optional parameters\n * Handles authentication check for private modals\n */\n const openModal = useCallback<IModalContext['openModal']>(\n (modalName, newModalParams) => {\n const newModal = modals.find(m => m.name === modalName);\n\n if (!newModal) {\n throw new Error(`Modal with name \"${modalName}\" not found`);\n }\n\n if (newModal.isPrivate && !isUserAuthenticated) {\n throw new Error(\n `Access violation: Modal \"${modalName}\" is private and user is not authenticated`,\n );\n }\n\n setIsClosing(false);\n setModal(newModal);\n setModalParams(newModalParams);\n lockScroll(); // Lock scroll while preserving scrollbar width\n },\n [isUserAuthenticated, modals],\n );\n\n const closeModal = useCallback(() => {\n setIsClosing(true);\n // Wait for the animation to complete before removing the modal\n unlockScroll();\n setTimeout(() => {\n setModal(null);\n setIsClosing(false);\n }, ANIMATION_DURATION_MS);\n }, []);\n\n const modalContent = useMemo<IModalContext>(\n () => ({\n modal,\n modalParams,\n openModal,\n closeModal,\n isClosing,\n }),\n [modal, modalParams, openModal, closeModal, isClosing],\n );\n\n useEffect(() => {\n if (!isUserAuthenticated && modal?.isPrivate) {\n // If the modal is private and user is not authenticated, close it\n closeModal();\n }\n }, [isUserAuthenticated, modal, closeModal]);\n\n // Handle ESC key\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && modal?.isDismissable !== false && !isClosing) {\n closeModal();\n }\n };\n\n window.addEventListener('keydown', handleKeyDown);\n\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [modal, closeModal, isClosing]);\n\n return (\n <ModalContext.Provider value={modalContent}>\n {children}\n {modal && <Modal modal={modal} isClosing={isClosing} onClose={closeModal} />}\n </ModalContext.Provider>\n );\n});\n\nexport default ModalProvider;\n"],"names":["ANIMATION_DURATION_MS","ModalProvider","memo","children","modals","isUserAuthenticated","modal","setModal","useState","modalParams","setModalParams","isClosing","setIsClosing","openModal","useCallback","modalName","newModalParams","newModal","m","lockScroll","closeModal","unlockScroll","modalContent","useMemo","useEffect","handleKeyDown","e","jsxs","ModalContext","jsx","Modal","ModalProvider$1"],"mappings":";;;;;AASA,MAAMA,IAAwB,KAKxBC,IAAyCC,EAAK,CAAC,EAAE,UAAAC,GAAU,QAAAC,GAAQ,qBAAAC,QAA0B;AACjG,QAAM,CAACC,GAAOC,CAAQ,IAAIC,EAAwB,IAAI,GAChD,CAACC,GAAaC,CAAc,IAAIF,EAA8C,MAAS,GACvF,CAACG,GAAWC,CAAY,IAAIJ,EAAS,EAAK,GAM1CK,IAAYC;AAAA,IAChB,CAACC,GAAWC,MAAmB;AAC7B,YAAMC,IAAWb,EAAO,KAAK,CAAKc,MAAAA,EAAE,SAASH,CAAS;AAEtD,UAAI,CAACE;AACH,cAAM,IAAI,MAAM,oBAAoBF,CAAS,aAAa;AAGxD,UAAAE,EAAS,aAAa,CAACZ;AACzB,cAAM,IAAI;AAAA,UACR,4BAA4BU,CAAS;AAAA,QAAA;AAIzC,MAAAH,EAAa,EAAK,GAClBL,EAASU,CAAQ,GACjBP,EAAeM,CAAc,GAClBG;IACb;AAAA,IACA,CAACd,GAAqBD,CAAM;AAAA,EAAA,GAGxBgB,IAAaN,EAAY,MAAM;AACnC,IAAAF,EAAa,EAAI,GAEJS,KACb,WAAW,MAAM;AACf,MAAAd,EAAS,IAAI,GACbK,EAAa,EAAK;AAAA,OACjBZ,CAAqB;AAAA,EAC1B,GAAG,CAAE,CAAA,GAECsB,IAAeC;AAAA,IACnB,OAAO;AAAA,MACL,OAAAjB;AAAA,MACA,aAAAG;AAAA,MACA,WAAAI;AAAA,MACA,YAAAO;AAAA,MACA,WAAAT;AAAA,IAAA;AAAA,IAEF,CAACL,GAAOG,GAAaI,GAAWO,GAAYT,CAAS;AAAA,EAAA;AAGvD,SAAAa,EAAU,MAAM;AACV,IAAA,CAACnB,MAAuBC,KAAA,QAAAA,EAAO,cAEtBc;EAEZ,GAAA,CAACf,GAAqBC,GAAOc,CAAU,CAAC,GAG3CI,EAAU,MAAM;AACR,UAAAC,IAAgB,CAACC,MAAqB;AAC1C,MAAIA,EAAE,QAAQ,aAAYpB,KAAA,gBAAAA,EAAO,mBAAkB,MAAS,CAACK,KAChDS;IACb;AAGK,kBAAA,iBAAiB,WAAWK,CAAa,GAEzC,MAAM,OAAO,oBAAoB,WAAWA,CAAa;AAAA,EAC/D,GAAA,CAACnB,GAAOc,GAAYT,CAAS,CAAC,GAG9B,gBAAAgB,EAAAC,EAAa,UAAb,EAAsB,OAAON,GAC3B,UAAA;AAAA,IAAAnB;AAAA,IACAG,KAAU,gBAAAuB,EAAAC,GAAA,EAAM,OAAAxB,GAAc,WAAAK,GAAsB,SAASS,GAAY;AAAA,EAC5E,EAAA,CAAA;AAEJ,CAAC,GAEDW,IAAe9B;"}
|
@@ -0,0 +1,154 @@
|
|
1
|
+
import o from "styled-components";
|
2
|
+
const s = o.div(
|
3
|
+
({ theme: { colors: a }, $isClosing: t }) => `
|
4
|
+
position: fixed;
|
5
|
+
top: 0;
|
6
|
+
left: 0;
|
7
|
+
right: 0;
|
8
|
+
bottom: 0;
|
9
|
+
background-color: ${a.BLACK_T_60};
|
10
|
+
backdrop-filter: blur(40px);
|
11
|
+
display: flex;
|
12
|
+
animation: ${t ? "backdropFadeOut" : "backdropFadeIn"} 0.2s ease-out forwards;
|
13
|
+
|
14
|
+
@keyframes backdropFadeIn {
|
15
|
+
from {
|
16
|
+
opacity: 0;
|
17
|
+
}
|
18
|
+
to {
|
19
|
+
opacity: 1;
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
@keyframes backdropFadeOut {
|
24
|
+
from {
|
25
|
+
opacity: 1;
|
26
|
+
}
|
27
|
+
to {
|
28
|
+
opacity: 0;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
`
|
32
|
+
), l = o.div(
|
33
|
+
({ theme: { colors: a }, $isClosing: t, $width: i }) => `
|
34
|
+
position: relative;
|
35
|
+
align-self: center;
|
36
|
+
margin: 0 auto;
|
37
|
+
width: ${i};
|
38
|
+
background-color: ${a.WHITE_1};
|
39
|
+
border: 1px solid ${a.BLACK_1};
|
40
|
+
transform-origin: center center;
|
41
|
+
animation: ${t ? "modalDisappear" : "modalAppear"} 0.5s cubic-bezier(0.19, 1, 0.22, 1) forwards;
|
42
|
+
box-shadow: 0px 10px 20px 0px rgba(0, 0, 0, 0.20);
|
43
|
+
|
44
|
+
/* Responsive behavior for smaller screens */
|
45
|
+
@media (max-width: calc(${i} + 80px)) {
|
46
|
+
width: 100%;
|
47
|
+
max-width: 100%;
|
48
|
+
height: 100%;
|
49
|
+
max-height: 100%;
|
50
|
+
border: none;
|
51
|
+
}
|
52
|
+
|
53
|
+
@keyframes modalAppear {
|
54
|
+
0% {
|
55
|
+
opacity: 0;
|
56
|
+
transform: perspective(1200px) translateZ(-50px) translateY(10px) scale(0.98);
|
57
|
+
}
|
58
|
+
100% {
|
59
|
+
opacity: 1;
|
60
|
+
transform: perspective(1200px) translateZ(0) translateY(0) scale(1);
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
@keyframes modalDisappear {
|
65
|
+
0% {
|
66
|
+
opacity: 1;
|
67
|
+
transform: perspective(1200px) translateZ(0) translateY(0) scale(1);
|
68
|
+
}
|
69
|
+
100% {
|
70
|
+
opacity: 0;
|
71
|
+
transform: perspective(1200px) translateZ(-50px) translateY(10px) scale(0.98);
|
72
|
+
}
|
73
|
+
}
|
74
|
+
`
|
75
|
+
), c = o.div(
|
76
|
+
({ $modalWidth: a }) => `
|
77
|
+
max-height: calc(100vh - 142px);
|
78
|
+
overflow-y: auto;
|
79
|
+
|
80
|
+
@media (max-width: calc(${a} + 80px)) {
|
81
|
+
max-height: 100vh;
|
82
|
+
}
|
83
|
+
}`
|
84
|
+
), m = o.div(
|
85
|
+
({ theme: { colors: a }, $modalWidth: t }) => `
|
86
|
+
position: absolute;
|
87
|
+
top: -56px;
|
88
|
+
right: -40px;
|
89
|
+
color: ${a.WHITE_1};
|
90
|
+
transition: all 0.2s ease;
|
91
|
+
|
92
|
+
&:hover {
|
93
|
+
transform: scale(1.05);
|
94
|
+
}
|
95
|
+
|
96
|
+
@media (max-width: calc(${t} + 80px)) {
|
97
|
+
top: 16px;
|
98
|
+
right: 16px;
|
99
|
+
color: ${a.BLACK_1};
|
100
|
+
}
|
101
|
+
`
|
102
|
+
), e = 720, r = 800, n = 500, d = o.div(
|
103
|
+
({ $isClosing: a }) => `
|
104
|
+
position: absolute;
|
105
|
+
width: ${e}px;
|
106
|
+
height: 100%;
|
107
|
+
left: 50%;
|
108
|
+
margin-left: ${-(e / 2)}px;
|
109
|
+
clip-path: polygon(calc(50% - 100px) 0, calc(50% + 100px) 0, 100% 100%, 0 100%);
|
110
|
+
background: linear-gradient(
|
111
|
+
180deg,
|
112
|
+
rgba(0, 0, 0, 1) 0%,
|
113
|
+
rgba(0, 0, 0, 0) 100%
|
114
|
+
);
|
115
|
+
animation: openSpotlight;
|
116
|
+
animation-duration: ${r}ms;
|
117
|
+
animation-timing-function: linear;
|
118
|
+
animation-fill-mode: forwards;
|
119
|
+
opacity: 0;
|
120
|
+
${a ? `
|
121
|
+
animation: closeSpotlight;
|
122
|
+
animation-duration: ${n}ms;
|
123
|
+
animation-timing-function: linear;
|
124
|
+
animation-fill-mode: forwards;
|
125
|
+
opacity: 1;
|
126
|
+
` : ""}
|
127
|
+
|
128
|
+
@keyframes openSpotlight {
|
129
|
+
from {
|
130
|
+
opacity: 0;
|
131
|
+
}
|
132
|
+
to {
|
133
|
+
opacity: 1;
|
134
|
+
}
|
135
|
+
}
|
136
|
+
|
137
|
+
@keyframes closeSpotlight {
|
138
|
+
from {
|
139
|
+
transform: rotateY(0);
|
140
|
+
}
|
141
|
+
to {
|
142
|
+
transform: rotateY(90deg);
|
143
|
+
}
|
144
|
+
}
|
145
|
+
`
|
146
|
+
);
|
147
|
+
export {
|
148
|
+
l as BaseModal,
|
149
|
+
c as BaseModalContent,
|
150
|
+
m as CloseButtonContainer,
|
151
|
+
s as ModalContainer,
|
152
|
+
d as SpotlightModal
|
153
|
+
};
|
154
|
+
//# sourceMappingURL=modal-styled.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"modal-styled.js","sources":["../../../../src/features/ui/modals/modal-styled.tsx"],"sourcesContent":["import styled from 'styled-components';\n\nconst ModalContainer = styled.div<{ $isClosing?: boolean }>(\n ({ theme: { colors }, $isClosing }) => `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: ${colors.BLACK_T_60};\n backdrop-filter: blur(40px);\n display: flex;\n animation: ${$isClosing ? 'backdropFadeOut' : 'backdropFadeIn'} 0.2s ease-out forwards;\n \n @keyframes backdropFadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n }\n \n @keyframes backdropFadeOut {\n from {\n opacity: 1;\n }\n to {\n opacity: 0;\n }\n }\n`,\n);\n\n/**\n * Base modal container with customizable width and animation state\n */\nconst BaseModal = styled.div<{\n $isClosing?: boolean;\n $width: string;\n}>(\n ({ theme: { colors }, $isClosing, $width }) => `\n position: relative;\n align-self: center;\n margin: 0 auto;\n width: ${$width};\n background-color: ${colors.WHITE_1};\n border: 1px solid ${colors.BLACK_1};\n transform-origin: center center;\n animation: ${\n $isClosing ? 'modalDisappear' : 'modalAppear'\n } 0.5s cubic-bezier(0.19, 1, 0.22, 1) forwards;\n box-shadow: 0px 10px 20px 0px rgba(0, 0, 0, 0.20);\n \n /* Responsive behavior for smaller screens */\n @media (max-width: calc(${$width} + 80px)) {\n width: 100%;\n max-width: 100%;\n height: 100%;\n max-height: 100%;\n border: none;\n }\n \n @keyframes modalAppear {\n 0% {\n opacity: 0;\n transform: perspective(1200px) translateZ(-50px) translateY(10px) scale(0.98);\n }\n 100% {\n opacity: 1;\n transform: perspective(1200px) translateZ(0) translateY(0) scale(1);\n }\n }\n \n @keyframes modalDisappear {\n 0% {\n opacity: 1;\n transform: perspective(1200px) translateZ(0) translateY(0) scale(1);\n }\n 100% {\n opacity: 0;\n transform: perspective(1200px) translateZ(-50px) translateY(10px) scale(0.98);\n }\n }\n`,\n);\n\n/**\n * Scrollable content container inside the modal\n */\nconst BaseModalContent = styled.div<{ $modalWidth: string }>(\n ({ $modalWidth }) => `\n max-height: calc(100vh - 142px);\n overflow-y: auto;\n\n @media (max-width: calc(${$modalWidth} + 80px)) {\n max-height: 100vh;\n }\n}`,\n);\n\n/**\n * Container for the close button with responsive positioning\n */\nconst CloseButtonContainer = styled.div<{ $modalWidth: string }>(\n ({ theme: { colors }, $modalWidth }) => `\n position: absolute;\n top: -56px;\n right: -40px;\n color: ${colors.WHITE_1};\n transition: all 0.2s ease;\n \n &:hover {\n transform: scale(1.05);\n }\n\n @media (max-width: calc(${$modalWidth} + 80px)) {\n top: 16px;\n right: 16px;\n color: ${colors.BLACK_1};\n }\n`,\n);\n\nconst spotlightWidth = 720;\nconst spotlightAnimationStartDuration = 800;\nconst spotlightAnimationEndDuration = 500;\n\nconst SpotlightModal = styled.div<{\n $isClosing?: boolean;\n}>(\n ({ $isClosing }) => `\n position: absolute;\n width: ${spotlightWidth}px;\n height: 100%;\n left: 50%;\n margin-left: ${-(spotlightWidth / 2)}px;\n clip-path: polygon(calc(50% - 100px) 0, calc(50% + 100px) 0, 100% 100%, 0 100%);\n background: linear-gradient(\n 180deg,\n rgba(0, 0, 0, 1) 0%,\n rgba(0, 0, 0, 0) 100%\n );\n animation: openSpotlight;\n animation-duration: ${spotlightAnimationStartDuration}ms;\n animation-timing-function: linear;\n animation-fill-mode: forwards;\n opacity: 0;\n ${\n $isClosing\n ? `\n animation: closeSpotlight;\n animation-duration: ${spotlightAnimationEndDuration}ms;\n animation-timing-function: linear;\n animation-fill-mode: forwards;\n opacity: 1;\n `\n : ''\n }\n\n @keyframes openSpotlight {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n }\n\n @keyframes closeSpotlight {\n from {\n transform: rotateY(0);\n }\n to {\n transform: rotateY(90deg);\n }\n }\n`,\n);\n\nexport { ModalContainer, BaseModal, BaseModalContent, CloseButtonContainer, SpotlightModal };\n"],"names":["ModalContainer","styled","colors","$isClosing","BaseModal","$width","BaseModalContent","$modalWidth","CloseButtonContainer","spotlightWidth","spotlightAnimationStartDuration","spotlightAnimationEndDuration","SpotlightModal"],"mappings":";AAEA,MAAMA,IAAiBC,EAAO;AAAA,EAC5B,CAAC,EAAE,OAAO,EAAE,QAAAC,EAAO,GAAG,YAAAC,EAAiB,MAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAMnBD,EAAO,UAAU;AAAA;AAAA;AAAA,eAGxBC,IAAa,oBAAoB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBhE,GAKMC,IAAYH,EAAO;AAAA,EAIvB,CAAC,EAAE,OAAO,EAAE,QAAAC,EAAU,GAAA,YAAAC,GAAY,QAAAE,QAAa;AAAA;AAAA;AAAA;AAAA,WAItCA,CAAM;AAAA,sBACKH,EAAO,OAAO;AAAA,sBACdA,EAAO,OAAO;AAAA;AAAA,eAGhCC,IAAa,mBAAmB,aAClC;AAAA;AAAA;AAAA;AAAA,4BAI0BE,CAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8BlC,GAKMC,IAAmBL,EAAO;AAAA,EAC9B,CAAC,EAAE,aAAAM,EAAA,MAAkB;AAAA;AAAA;AAAA;AAAA,4BAIKA,CAAW;AAAA;AAAA;AAAA;AAIvC,GAKMC,IAAuBP,EAAO;AAAA,EAClC,CAAC,EAAE,OAAO,EAAE,QAAAC,EAAO,GAAG,aAAAK,EAAkB,MAAA;AAAA;AAAA;AAAA;AAAA,WAI/BL,EAAO,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BAOGK,CAAW;AAAA;AAAA;AAAA,aAG1BL,EAAO,OAAO;AAAA;AAAA;AAG3B,GAEMO,IAAiB,KACjBC,IAAkC,KAClCC,IAAgC,KAEhCC,IAAiBX,EAAO;AAAA,EAG5B,CAAC,EAAE,YAAAE,EAAA,MAAiB;AAAA;AAAA,WAEXM,CAAc;AAAA;AAAA;AAAA,iBAGR,EAAEA,IAAiB,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAQdC,CAA+B;AAAA;AAAA;AAAA;AAAA,IAKnDP,IACI;AAAA;AAAA,4BAEoBQ,CAA6B;AAAA;AAAA;AAAA;AAAA,QAKjD,EACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBF;"}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import { jsxs as t, jsx as o } from "react/jsx-runtime";
|
2
|
+
import { memo as m } from "react";
|
3
|
+
import h from "../../../assets/line-icons/icons/cross.js";
|
4
|
+
import c from "../buttons/clickable/clickable.js";
|
5
|
+
import { ModalContainer as r, SpotlightModal as f, BaseModal as C, CloseButtonContainer as p, BaseModalContent as $ } from "./modal-styled.js";
|
6
|
+
const B = m(({ modal: n, isClosing: e = !1, onClose: s }) => {
|
7
|
+
const { renderAs: d, element: l, modalWidth: i, isDismissable: a } = n;
|
8
|
+
return d === "spotlight" ? /* @__PURE__ */ t(r, { $isClosing: e, children: [
|
9
|
+
/* @__PURE__ */ o(f, { $isClosing: e }),
|
10
|
+
l
|
11
|
+
] }) : /* @__PURE__ */ o(r, { $isClosing: e, children: /* @__PURE__ */ t(C, { $isClosing: e, $width: i, children: [
|
12
|
+
a !== !1 && /* @__PURE__ */ o(p, { $modalWidth: i, children: /* @__PURE__ */ o(c, { label: "Close", onClick: s, children: /* @__PURE__ */ o(h, { width: 40, height: 40 }) }) }),
|
13
|
+
/* @__PURE__ */ o($, { $modalWidth: i, children: l })
|
14
|
+
] }) });
|
15
|
+
});
|
16
|
+
export {
|
17
|
+
B as default
|
18
|
+
};
|
19
|
+
//# sourceMappingURL=modal.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"modal.js","sources":["../../../../src/features/ui/modals/modal.tsx"],"sourcesContent":["import type { IModalProps } from './modal-types';\nimport type { FC } from 'react';\n\nimport { memo } from 'react';\n\nimport CrossIcon from '../../../assets/line-icons/icons/cross';\nimport Clickable from '../buttons/clickable/clickable';\nimport * as Styled from './modal-styled';\n\n/**\n * Modal component that renders modal content with close button\n * Handles animation state for entry and exit transitions\n */\nconst Modal: FC<IModalProps> = memo(({ modal, isClosing = false, onClose }) => {\n const { renderAs, element, modalWidth, isDismissable } = modal;\n\n if (renderAs === 'spotlight') {\n return (\n <Styled.ModalContainer $isClosing={isClosing}>\n <Styled.SpotlightModal $isClosing={isClosing} />\n {element}\n </Styled.ModalContainer>\n );\n }\n\n return (\n <Styled.ModalContainer $isClosing={isClosing}>\n <Styled.BaseModal $isClosing={isClosing} $width={modalWidth}>\n {isDismissable !== false && (\n <Styled.CloseButtonContainer $modalWidth={modalWidth}>\n <Clickable label=\"Close\" onClick={onClose}>\n <CrossIcon width={40} height={40} />\n </Clickable>\n </Styled.CloseButtonContainer>\n )}\n <Styled.BaseModalContent $modalWidth={modalWidth}>{element}</Styled.BaseModalContent>\n </Styled.BaseModal>\n </Styled.ModalContainer>\n );\n});\n\nexport default Modal;\n"],"names":["Modal","memo","modal","isClosing","onClose","renderAs","element","modalWidth","isDismissable","jsxs","Styled.ModalContainer","jsx","Styled.SpotlightModal","Styled.BaseModal","Styled.CloseButtonContainer","Clickable","CrossIcon","Styled.BaseModalContent"],"mappings":";;;;;AAaM,MAAAA,IAAyBC,EAAK,CAAC,EAAE,OAAAC,GAAO,WAAAC,IAAY,IAAO,SAAAC,QAAc;AAC7E,QAAM,EAAE,UAAAC,GAAU,SAAAC,GAAS,YAAAC,GAAY,eAAAC,MAAkBN;AAEzD,SAAIG,MAAa,cAEZ,gBAAAI,EAAAC,GAAA,EAAsB,YAAYP,GACjC,UAAA;AAAA,IAAA,gBAAAQ,EAACC,GAAA,EAAsB,YAAYT,EAAW,CAAA;AAAA,IAC7CG;AAAA,EACH,EAAA,CAAA,IAKD,gBAAAK,EAAAD,GAAA,EAAsB,YAAYP,GACjC,UAAC,gBAAAM,EAAAI,GAAA,EAAiB,YAAYV,GAAW,QAAQI,GAC9C,UAAA;AAAA,IAAkBC,MAAA,wBAChBM,GAAA,EAA4B,aAAaP,GACxC,4BAACQ,GAAU,EAAA,OAAM,SAAQ,SAASX,GAChC,4BAACY,GAAU,EAAA,OAAO,IAAI,QAAQ,IAAI,GACpC,EACF,CAAA;AAAA,sBAEDC,GAAA,EAAwB,aAAaV,GAAa,UAAQD,GAAA;AAAA,EAAA,EAC7D,CAAA,EACF,CAAA;AAEJ,CAAC;"}
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import { useContext as e } from "react";
|
2
|
+
import n from "./modal-context.js";
|
3
|
+
const l = () => {
|
4
|
+
const { openModal: o, closeModal: t, isClosing: s } = e(n);
|
5
|
+
return { openModal: o, closeModal: t, isClosing: s };
|
6
|
+
}, c = l;
|
7
|
+
export {
|
8
|
+
c as default
|
9
|
+
};
|
10
|
+
//# sourceMappingURL=use-modal-actions.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"use-modal-actions.js","sources":["../../../../src/features/ui/modals/use-modal-actions.ts"],"sourcesContent":["import type { IUseModalActions } from './modal-types';\n\nimport { useContext } from 'react';\n\nimport ModalContext from './modal-context';\n\nconst useModalActions: IUseModalActions = () => {\n const { openModal, closeModal, isClosing } = useContext(ModalContext);\n\n return { openModal, closeModal, isClosing };\n};\n\nexport default useModalActions;\n"],"names":["useModalActions","openModal","closeModal","isClosing","useContext","ModalContext","useModalActions$1"],"mappings":";;AAMA,MAAMA,IAAoC,MAAM;AAC9C,QAAM,EAAE,WAAAC,GAAW,YAAAC,GAAY,WAAAC,EAAU,IAAIC,EAAWC,CAAY;AAE7D,SAAA,EAAE,WAAAJ,GAAW,YAAAC,GAAY,WAAAC;AAClC,GAEAG,IAAeN;"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"use-modal-params.js","sources":["../../../../src/features/ui/modals/use-modal-params.ts"],"sourcesContent":["import type { IUseModalParams } from './modal-types';\n\nimport { useContext } from 'react';\n\nimport ModalContext from './modal-context';\n\nconst useModalParams: IUseModalParams = <\n T extends Record<string, unknown> | undefined = undefined,\n>(): T => {\n const { modalParams } = useContext(ModalContext);\n\n return modalParams as T;\n};\n\nexport default useModalParams;\n"],"names":["useModalParams","modalParams","useContext","ModalContext","useModalParams$1"],"mappings":";;AAMA,MAAMA,IAAkC,MAE9B;AACR,QAAM,EAAE,aAAAC,EAAA,IAAgBC,EAAWC,CAAY;AAExC,SAAAF;AACT,GAEAG,IAAeJ;"}
|
package/dist/index.d.ts
CHANGED
@@ -2360,6 +2360,45 @@ declare interface IMilestoneWidgetResourcesProps extends INodeCardCallbacks {
|
|
2360
2360
|
canUpdatePlan?: boolean;
|
2361
2361
|
}
|
2362
2362
|
|
2363
|
+
/**
|
2364
|
+
* Configuration for a modal component
|
2365
|
+
*/
|
2366
|
+
declare interface IModal {
|
2367
|
+
/** Unique identifier for the modal */
|
2368
|
+
name: string;
|
2369
|
+
/** Content to display inside the modal */
|
2370
|
+
element: JSX.Element;
|
2371
|
+
/** Rendering style of the modal */
|
2372
|
+
renderAs?: 'modal' | 'fullscreen' | 'spotlight';
|
2373
|
+
/** Whether the modal can be dismissed by clicking outside or ESC key (default: true) */
|
2374
|
+
isDismissable?: boolean;
|
2375
|
+
/** Whether the modal requires authentication to view (default: true) */
|
2376
|
+
isPrivate?: boolean;
|
2377
|
+
/** Width of the modal in CSS units (e.g., '500px', '80vw') */
|
2378
|
+
modalWidth: string;
|
2379
|
+
}
|
2380
|
+
|
2381
|
+
/**
|
2382
|
+
* Context for managing modals throughout the application
|
2383
|
+
*/
|
2384
|
+
declare interface IModalContext {
|
2385
|
+
/** Currently active modal or null if no modal is open */
|
2386
|
+
modal: IModal | null;
|
2387
|
+
/** Parameters passed to the modal when opened */
|
2388
|
+
modalParams?: Record<string, unknown>;
|
2389
|
+
/** Opens a modal by name with optional parameters */
|
2390
|
+
openModal: (name: string, params?: Record<string, unknown>) => void;
|
2391
|
+
/** Closes the currently open modal */
|
2392
|
+
closeModal: () => void;
|
2393
|
+
/** Whether the modal is in the process of closing (for animation) */
|
2394
|
+
isClosing?: boolean;
|
2395
|
+
}
|
2396
|
+
|
2397
|
+
declare interface IModalProviderProps extends PropsWithChildren {
|
2398
|
+
modals: IModal[];
|
2399
|
+
isUserAuthenticated?: boolean;
|
2400
|
+
}
|
2401
|
+
|
2363
2402
|
export declare interface IMultiplayerWebGameProps extends IBaseWebGameProps, ISyncableWebGameProps {
|
2364
2403
|
enablePlayerTurnIndicators?: boolean;
|
2365
2404
|
}
|
@@ -3564,6 +3603,14 @@ declare interface IUseIsTabBlocked {
|
|
3564
3603
|
(): IMultiTabBlockerContextValue;
|
3565
3604
|
}
|
3566
3605
|
|
3606
|
+
declare interface IUseModalActions {
|
3607
|
+
(): Pick<IModalContext, 'openModal' | 'closeModal' | 'isClosing'>;
|
3608
|
+
}
|
3609
|
+
|
3610
|
+
declare interface IUseModalParams {
|
3611
|
+
<T extends Record<string, unknown> | undefined = undefined>(): T;
|
3612
|
+
}
|
3613
|
+
|
3567
3614
|
declare interface IusePointerSyncMethods {
|
3568
3615
|
publishMouseMove?: (data: IPointerData) => void;
|
3569
3616
|
susbcribeMouseMove?: (qrId: string, cb: (data: IPointerData) => void) => void;
|
@@ -4116,6 +4163,11 @@ export declare const MistakeIcon: React.FC<React.SVGProps<SVGSVGElement>>;
|
|
4116
4163
|
|
4117
4164
|
export declare const Mobile: React.FC<React.SVGProps<SVGSVGElement>>;
|
4118
4165
|
|
4166
|
+
/**
|
4167
|
+
* Provider component that manages modal state and provides modal context to child components
|
4168
|
+
*/
|
4169
|
+
export declare const ModalProvider: FC<IModalProviderProps>;
|
4170
|
+
|
4119
4171
|
export declare const MoreVerticalIcon: React.FC<React.SVGProps<SVGSVGElement>>;
|
4120
4172
|
|
4121
4173
|
export declare const MultiTabBlocker: FC<PropsWithChildren<IMultiTabBlockerProps>>;
|
@@ -5830,6 +5882,10 @@ export declare const useIsTabBlocked: IUseIsTabBlocked;
|
|
5830
5882
|
|
5831
5883
|
export declare const useJourney: () => IJourneyContext;
|
5832
5884
|
|
5885
|
+
export declare const useModalActions: IUseModalActions;
|
5886
|
+
|
5887
|
+
export declare const useModalParams: IUseModalParams;
|
5888
|
+
|
5833
5889
|
export declare const usePointerSync: ({ userType, targetUserId, }: IusePointerSyncProps) => IusePointerSyncMethods;
|
5834
5890
|
|
5835
5891
|
export declare const User2Icon: React.FC<React.SVGProps<SVGSVGElement>>;
|